├── .github ├── FUNDING.yml └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── .goreleaser.yaml ├── LICENSE ├── Makefile ├── README.md ├── go.mod ├── go.sum ├── internal └── backupnode │ ├── Dockerfile │ ├── bootstrap.go │ ├── config.go │ ├── config.yml │ ├── docker-compose.yml │ └── netconf.go └── main.go /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [clems4ever] 4 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: '*' 6 | 7 | permissions: 8 | contents: write 9 | # packages: write 10 | # issues: write 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | with: 18 | fetch-depth: 0 19 | - run: git fetch --force --tags 20 | - uses: actions/setup-go@v4 21 | with: 22 | go-version: stable 23 | - uses: goreleaser/goreleaser-action@v4 24 | with: 25 | distribution: goreleaser 26 | version: latest 27 | args: build --snapshot 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: goreleaser 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | permissions: 9 | contents: write 10 | # packages: write 11 | # issues: write 12 | 13 | jobs: 14 | goreleaser: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | with: 19 | fetch-depth: 0 20 | - run: git fetch --force --tags 21 | - uses: actions/setup-go@v4 22 | with: 23 | go-version: stable 24 | - uses: goreleaser/goreleaser-action@v4 25 | with: 26 | distribution: goreleaser 27 | version: latest 28 | args: release --clean 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | configurations/ 2 | 3 | /.config.yml 4 | /config.yml 5 | dist/ 6 | anytype-backup-node* 7 | 8 | /backupnode.env 9 | /docker-compose.yml 10 | /Dockerfile -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | # This is an example .goreleaser.yml file with some sensible defaults. 2 | # Make sure to check the documentation at https://goreleaser.com 3 | before: 4 | hooks: 5 | # You may remove this if you don't use go modules. 6 | - go mod tidy 7 | # you may remove this if you don't need go generate 8 | # - go generate ./... 9 | builds: 10 | - env: 11 | - CGO_ENABLED=0 12 | goos: 13 | - linux 14 | - windows 15 | - darwin 16 | 17 | archives: 18 | - format: binary 19 | # this name template makes the OS and Arch compatible with the results of uname. 20 | name_template: >- 21 | {{ .ProjectName }}_ 22 | {{- title .Os }}_ 23 | {{- if eq .Arch "amd64" }}x86_64 24 | {{- else if eq .Arch "386" }}i386 25 | {{- else }}{{ .Arch }}{{ end }} 26 | {{- if .Arm }}v{{ .Arm }}{{ end }} 27 | # use zip for windows archives 28 | format_overrides: 29 | - goos: windows 30 | format: zip 31 | checksum: 32 | name_template: 'checksums.txt' 33 | snapshot: 34 | name_template: "{{ incpatch .Version }}-next" 35 | changelog: 36 | sort: asc 37 | filters: 38 | exclude: 39 | - '^docs:' 40 | - '^test:' 41 | 42 | # The lines beneath this are called `modelines`. See `:help modeline` 43 | # Feel free to remove those if you don't want/use them. 44 | # yaml-language-server: $schema=https://goreleaser.com/static/schema.json 45 | # vim: set ts=2 sw=2 tw=0 fo=cnqoj 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Clément Michaud 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | goreleaser build --snapshot 4 | 5 | clean: 6 | rm -rf dist -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AnyType Dockerized Backup Node 2 | 3 | [AnyType](https://anytype.io/) is this incredible note-taking app that was released in the 4 | opensource. 5 | 6 | This project aims to spawn a AnyType self-hosted dockerized backup node for keeping your personal data private on 7 | your own devices and network. Note that keeping the data on AnyType servers is fine in terms of security and 8 | privacy because it is end-to-end encrypted. However, having a self-hosted backup node provides an extra layer of 9 | security as well as a bigger space than 1GB for storing files but at the **non-negligible** cost of maintaining 10 | the infrastructure. 11 | 12 | Please note that, as easy as it is to spawn a backup node with this project, it is not the only thing to do 13 | to end up with a fully working self-hosted setup including clients. I would highly advise not to use this project if 14 | you do not have a deep understanding of the internals of anytype because fixing and upgrading this infrastructure is 15 | not an easy thing. Moreover, you will still need to build the clients for your devices, which is definitely not a 16 | no-brainer. 17 | 18 | *This project is my own independant contribution to the Anytype project, therefore it is not maintained by the 19 | Anytype team.* 20 | 21 | ## Disclaimer of Liability 22 | 23 | Please be advised that by using this project, you agree to do so at your own risk. While every effort has been 24 | made to ensure the integrity and security of the code, I cannot be held liable for any damage, loss, or 25 | corruption of data that may occur as a result of using this project. It is strongly recommended that you back 26 | up all important data and thoroughly review the code and documentation before implementation. By proceeding with 27 | the use of this project, you acknowledge and accept full responsibility for any and all potential consequences. 28 | 29 | ## Getting Started 30 | 31 | With the Liability disclaimer out of the way, let's first make sure Docker and docker-compose are installed on your 32 | machine before anything else. 33 | 34 | Then, download the latest release of [anytype-backup-node](https://github.com/clems4ever/anytype-backup-node/releases). 35 | On Linux and Mac, make sure you make the binary executable with 36 | 37 | ```bash 38 | chmod +x anytype-backup-node_Linux_x86_64 39 | ``` 40 | 41 | You can now run the following command to generate a [default configuration](./internal/backupnode/config.yml) that you 42 | can edit before spawning the infrastructure. 43 | 44 | ```bash 45 | # generate the default config.yml file. 46 | ./anytype-backup-node_Linux_x86_64 init 47 | ``` 48 | 49 | Once the configuration file is ready, run the following command to bootstrap the services of the backup node. 50 | 51 | ```bash 52 | # spawn the services. 53 | ./anytype-backup-node_Linux_x86_64 bootstrap 54 | ``` 55 | 56 | Now, you should have all services running. However, as documented above you need to build the clients for your devices with 57 | the proper anytype configuration. The anytype configuration files including `heart.yml` are accessible for your to review in 58 | `configurations/` unless you modified the path in your configuration. 59 | 60 | This project does not build the clients because the Anytype team is working on a way to  [customize the clients without rebuilding 61 | them](https://github.com/orgs/anyproto/discussions/17#discussioncomment-6651683) and it will be released soon enough. 62 | 63 | ## Where is the Dockerfile and docker-compose.yml? 64 | 65 | The files are embedded in the go application that you can download from the 66 | [release tab](https://github.com/clems4ever/anytype-backup-node/releases) but if you want you can check the source of the 67 | [Dockerfile](./internal/backupnode/Dockerfile) and the [docker-compose.yml](./internal/backupnode/docker-compose.yml) file. 68 | 69 | ## Contributions and testing 70 | 71 | This project has been tested on a Linux server. I've manually verified that the space is synced and that files are 72 | stored in the file node by checking the content of MinIO and Redis. 73 | 74 | Those tests are not automated yet so if you are willing to contribute, make sure you fully test 75 | your changes yourself and prove it with some automated tests or at least some screenshots. 76 | 77 | ## Next 78 | 79 | - Authenticate redis 80 | 81 | ## Sponsorship 82 | 83 | You can thank me by sponsoring me on [Github](https://github.com/sponsors/clems4ever) 84 | 85 | or 86 | 87 | You can buy me a beer in the crypto sphere on Ethereum or Polygon at [0x92a9C9e6a418712252fB5996CfE3391a7baBBffB](https://etherscan.io/address/0x92a9C9e6a418712252fB5996CfE3391a7baBBffB). 88 | 89 | ## License 90 | 91 | This project is licensed under the [MIT license](./LICENSE). 92 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/clems4ever/anytype-backup-node 2 | 3 | go 1.20 4 | 5 | replace github.com/anyproto/any-sync-tools => github.com/clems4ever/any-sync-tools v0.0.0-20230806094649-e456cacce2f9 6 | 7 | require ( 8 | github.com/anyproto/any-sync-tools v0.0.0-00010101000000-000000000000 9 | github.com/minio/minio-go/v7 v7.0.61 10 | github.com/spf13/cobra v1.7.0 11 | ) 12 | 13 | require ( 14 | gopkg.in/yaml.v2 v2.4.0 // indirect 15 | gopkg.in/yaml.v3 v3.0.1 16 | ) 17 | 18 | require ( 19 | filippo.io/edwards25519 v1.0.0 // indirect 20 | github.com/AlecAivazis/survey/v2 v2.3.7 // indirect 21 | github.com/anyproto/any-sync v0.2.14 // indirect 22 | github.com/anyproto/go-slip10 v1.0.0 // indirect 23 | github.com/anyproto/go-slip21 v1.0.0 // indirect 24 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect 25 | github.com/dustin/go-humanize v1.0.1 // indirect 26 | github.com/gobwas/glob v0.2.3 // indirect 27 | github.com/gogo/protobuf v1.3.2 // indirect 28 | github.com/google/uuid v1.3.0 // indirect 29 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 30 | github.com/ipfs/go-cid v0.4.1 // indirect 31 | github.com/json-iterator/go v1.1.12 // indirect 32 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect 33 | github.com/klauspost/compress v1.16.7 // indirect 34 | github.com/klauspost/cpuid/v2 v2.2.5 // indirect 35 | github.com/libp2p/go-buffer-pool v0.1.0 // indirect 36 | github.com/libp2p/go-libp2p v0.28.1 // indirect 37 | github.com/mattn/go-colorable v0.1.2 // indirect 38 | github.com/mattn/go-isatty v0.0.19 // indirect 39 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect 40 | github.com/minio/md5-simd v1.1.2 // indirect 41 | github.com/minio/sha256-simd v1.0.1 // indirect 42 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 43 | github.com/modern-go/reflect2 v1.0.2 // indirect 44 | github.com/mr-tron/base58 v1.2.0 // indirect 45 | github.com/multiformats/go-base32 v0.1.0 // indirect 46 | github.com/multiformats/go-base36 v0.2.0 // indirect 47 | github.com/multiformats/go-multiaddr v0.9.0 // indirect 48 | github.com/multiformats/go-multibase v0.2.0 // indirect 49 | github.com/multiformats/go-multicodec v0.9.0 // indirect 50 | github.com/multiformats/go-multihash v0.2.3 // indirect 51 | github.com/multiformats/go-varint v0.0.7 // indirect 52 | github.com/rs/xid v1.5.0 // indirect 53 | github.com/sirupsen/logrus v1.9.3 // indirect 54 | github.com/spaolacci/murmur3 v1.1.0 // indirect 55 | github.com/spf13/pflag v1.0.5 // indirect 56 | github.com/tyler-smith/go-bip39 v1.1.0 // indirect 57 | go.uber.org/atomic v1.11.0 // indirect 58 | go.uber.org/multierr v1.11.0 // indirect 59 | go.uber.org/zap v1.24.0 // indirect 60 | golang.org/x/crypto v0.11.0 // indirect 61 | golang.org/x/net v0.12.0 // indirect 62 | golang.org/x/sys v0.10.0 // indirect 63 | golang.org/x/term v0.10.0 // indirect 64 | golang.org/x/text v0.11.0 // indirect 65 | google.golang.org/protobuf v1.30.0 // indirect 66 | gopkg.in/ini.v1 v1.67.0 // indirect 67 | gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect 68 | lukechampine.com/blake3 v1.2.1 // indirect 69 | ) 70 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= 2 | filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= 3 | github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= 4 | github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= 5 | github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= 6 | github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= 7 | github.com/anyproto/any-sync v0.2.14 h1:nu9y+JkeD8UQXpRMDqRK9PyfEhCFaMhzXSlUoG/gmqw= 8 | github.com/anyproto/any-sync v0.2.14/go.mod h1:DSylRQYM/tTWZ8B6hZwsOFgLFupakVvhbZh7thE8V+g= 9 | github.com/anyproto/go-slip10 v1.0.0 h1:uAEtSuudR3jJBOfkOXf3bErxVoxbuKwdoJN55M1i6IA= 10 | github.com/anyproto/go-slip10 v1.0.0/go.mod h1:BCmIlM1KB8wX6K4/8pOvxPl9oVKfEvZ5vsmO5rkK6vg= 11 | github.com/anyproto/go-slip21 v1.0.0 h1:CI7lUqTIwmPOEGVAj4jyNLoICvueh++0U2HoAi3m2ZY= 12 | github.com/anyproto/go-slip21 v1.0.0/go.mod h1:gbIJt7HAdr5DuT4f2pFTKCBSUWYsm/fysHBNqgsuxT0= 13 | github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= 14 | github.com/clems4ever/any-sync-tools v0.0.0-20230806094649-e456cacce2f9 h1:hNbdJUWo7g5njziTZhfVNIfisioTngU2xn/SIrjdWUQ= 15 | github.com/clems4ever/any-sync-tools v0.0.0-20230806094649-e456cacce2f9/go.mod h1:pNP+iMhflhEMS30hex2YcSI2wbbSubwbcfhGcs3zCDw= 16 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 17 | github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= 18 | github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= 19 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 20 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 21 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 22 | github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= 23 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= 24 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= 25 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 26 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 27 | github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= 28 | github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 29 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 30 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 31 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 32 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 33 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 34 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 35 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 36 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 37 | github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= 38 | github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= 39 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 40 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 41 | github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= 42 | github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= 43 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 44 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 45 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= 46 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= 47 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 48 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 49 | github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= 50 | github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= 51 | github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 52 | github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= 53 | github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 54 | github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= 55 | github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= 56 | github.com/libp2p/go-libp2p v0.28.1 h1:YurK+ZAI6cKfASLJBVFkpVBdl3wGhFi6fusOt725ii8= 57 | github.com/libp2p/go-libp2p v0.28.1/go.mod h1:s3Xabc9LSwOcnv9UD4nORnXKTsWkPMkIMB/JIGXVnzk= 58 | github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= 59 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 60 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 61 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= 62 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 63 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= 64 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 65 | github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= 66 | github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= 67 | github.com/minio/minio-go/v7 v7.0.61 h1:87c+x8J3jxQ5VUGimV9oHdpjsAvy3fhneEBKuoKEVUI= 68 | github.com/minio/minio-go/v7 v7.0.61/go.mod h1:BTu8FcrEw+HidY0zd/0eny43QnVNkXRPXrLXFuQBHXg= 69 | github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= 70 | github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= 71 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 72 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 73 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 74 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 75 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 76 | github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= 77 | github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 78 | github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= 79 | github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= 80 | github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= 81 | github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= 82 | github.com/multiformats/go-multiaddr v0.9.0 h1:3h4V1LHIk5w4hJHekMKWALPXErDfz/sggzwC/NcqbDQ= 83 | github.com/multiformats/go-multiaddr v0.9.0/go.mod h1:mI67Lb1EeTOYb8GQfL/7wpIZwc46ElrvzhYnoJOmTT0= 84 | github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= 85 | github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= 86 | github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= 87 | github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= 88 | github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= 89 | github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= 90 | github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= 91 | github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= 92 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 93 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 94 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 95 | github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= 96 | github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 97 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 98 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 99 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 100 | github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= 101 | github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 102 | github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= 103 | github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= 104 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 105 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 106 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 107 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 108 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 109 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 110 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 111 | github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= 112 | github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= 113 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 114 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 115 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 116 | go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= 117 | go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= 118 | go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= 119 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 120 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 121 | go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= 122 | go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= 123 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 124 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 125 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 126 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 127 | golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= 128 | golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= 129 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 130 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 131 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 132 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 133 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 134 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 135 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 136 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 137 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 138 | golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= 139 | golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= 140 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 141 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 142 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 143 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 144 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 145 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 146 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 147 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 148 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 149 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 150 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 151 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 152 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 153 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 154 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 155 | golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= 156 | golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 157 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 158 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 159 | golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= 160 | golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= 161 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 162 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 163 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 164 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 165 | golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= 166 | golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 167 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 168 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 169 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 170 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 171 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 172 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 173 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 174 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 175 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 176 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 177 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 178 | google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= 179 | google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 180 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 181 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 182 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 183 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 184 | gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= 185 | gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= 186 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 187 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 188 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 189 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 190 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 191 | lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= 192 | lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= 193 | -------------------------------------------------------------------------------- /internal/backupnode/Dockerfile: -------------------------------------------------------------------------------- 1 | # any-sync-coordinator 2 | FROM golang:1.20-bullseye AS any-sync-coordinator 3 | LABEL MAINTAINER="Clément Michaud " 4 | 5 | WORKDIR /usr/app 6 | 7 | RUN git clone --depth 1 --branch v0.2.6 https://github.com/anyproto/any-sync-coordinator.git 8 | RUN cd any-sync-coordinator && make deps && make build 9 | 10 | CMD ["/usr/app/any-sync-coordinator/bin/any-sync-coordinator", "-c", "/etc/anytype/coordinator.yml"] 11 | 12 | # any-sync-node 13 | FROM golang:1.20-bullseye AS any-sync-node 14 | LABEL MAINTAINER="Clément Michaud " 15 | 16 | WORKDIR /usr/app 17 | 18 | RUN git clone --depth 1 --branch v0.2.8 https://github.com/anyproto/any-sync-node.git 19 | RUN cd any-sync-node && make deps && make build 20 | RUN mkdir /usr/app/db 21 | 22 | CMD ["/usr/app/any-sync-node/bin/any-sync-node", "-c", "/etc/anytype/sync_1.yml"] 23 | 24 | # any-sync-filenode 25 | FROM golang:1.20-bullseye AS any-sync-filenode 26 | LABEL MAINTAINER="Clément Michaud " 27 | 28 | WORKDIR /usr/app 29 | 30 | RUN git clone --depth 1 --branch v0.3.5 https://github.com/anyproto/any-sync-filenode.git 31 | RUN cd any-sync-filenode && make deps && make build 32 | 33 | CMD ["/usr/app/any-sync-filenode/bin/any-sync-filenode", "-c", "/etc/anytype/file_1.yml"] 34 | -------------------------------------------------------------------------------- /internal/backupnode/bootstrap.go: -------------------------------------------------------------------------------- 1 | package backupnode 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "os" 8 | "os/exec" 9 | "time" 10 | 11 | "github.com/minio/minio-go/v7" 12 | "github.com/minio/minio-go/v7/pkg/credentials" 13 | "gopkg.in/yaml.v3" 14 | ) 15 | 16 | func dockerCompose(args ...string) { 17 | cmd := exec.Command("docker-compose", args...) 18 | 19 | cmd.Stdout = os.Stdout 20 | cmd.Stderr = os.Stderr 21 | 22 | err := cmd.Run() 23 | if err != nil { 24 | log.Fatal(err) 25 | } 26 | } 27 | 28 | func GenerateConfig(configPath string) { 29 | GenerateNetworkConfig(configPath) 30 | 31 | b, err := os.ReadFile(configPath) 32 | if err != nil { 33 | log.Fatal(err) 34 | } 35 | 36 | var cfg Config 37 | err = yaml.Unmarshal(b, &cfg) 38 | if err != nil { 39 | log.Fatal(err) 40 | } 41 | 42 | envFileContent := "" 43 | envFileContent += fmt.Sprintf("MINIO_ROOT_USER=%s", cfg.MinioUser) + "\n" 44 | envFileContent += fmt.Sprintf("MINIO_ROOT_PASSWORD=%s", cfg.MinioPassword) + "\n" 45 | envFileContent += fmt.Sprintf("MONGO_INITDB_ROOT_USERNAME=%s", cfg.MongoUser) + "\n" 46 | envFileContent += fmt.Sprintf("MONGO_INITDB_ROOT_PASSWORD=%s", cfg.MongoPassword) + "\n" 47 | dumpFile("backupnode.env", envFileContent) 48 | } 49 | 50 | func Bootstrap(ctx context.Context, configPath string) { 51 | GenerateConfig(configPath) 52 | 53 | dockerCompose("up", "--build", "-d") 54 | 55 | fmt.Println("Waiting for the infrastructure to boot...") 56 | time.Sleep(time.Second) 57 | 58 | Initialize(ctx, configPath) 59 | } 60 | 61 | func Initialize(ctx context.Context, configPath string) { 62 | b, err := os.ReadFile(configPath) 63 | if err != nil { 64 | log.Fatal(err) 65 | } 66 | 67 | var cfg Config 68 | err = yaml.Unmarshal(b, &cfg) 69 | if err != nil { 70 | log.Fatal(err) 71 | } 72 | 73 | endpoint := fmt.Sprintf("%s:9000", cfg.HostIP) 74 | accessKeyID := cfg.MinioUser 75 | secretAccessKey := cfg.MinioPassword 76 | 77 | // Initialize minio client object. 78 | minioClient, err := minio.New(endpoint, &minio.Options{ 79 | Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""), 80 | }) 81 | if err != nil { 82 | log.Fatalln(err) 83 | } 84 | 85 | bucketName := "any-sync-files" 86 | location := "eu-central-1" 87 | 88 | newCtx, cancel := context.WithTimeout(ctx, 5*time.Second) 89 | defer cancel() 90 | 91 | fmt.Println("Trying to create minio bucket...") 92 | err = minioClient.MakeBucket(newCtx, bucketName, minio.MakeBucketOptions{Region: location}) 93 | if err != nil { 94 | // Check to see if we already own this bucket (which happens if you run this twice) 95 | exists, errBucketExists := minioClient.BucketExists(newCtx, bucketName) 96 | if errBucketExists == nil && exists { 97 | log.Printf("We already own %s\n", bucketName) 98 | } else { 99 | log.Fatalln(err) 100 | } 101 | } else { 102 | log.Printf("Successfully created bucket %s in minio\n", bucketName) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /internal/backupnode/config.go: -------------------------------------------------------------------------------- 1 | package backupnode 2 | 3 | import ( 4 | "log" 5 | "os" 6 | 7 | _ "embed" 8 | ) 9 | 10 | //go:embed config.yml 11 | var configFile string 12 | 13 | //go:embed Dockerfile 14 | var dockerfile string 15 | 16 | //go:embed docker-compose.yml 17 | var dockerComposeFile string 18 | 19 | func dumpFile(path string, content string) { 20 | err := os.WriteFile(path, []byte(content), 0600) 21 | if err != nil { 22 | log.Fatal(err) 23 | } 24 | } 25 | 26 | func Init() { 27 | err := os.WriteFile("config.yml", []byte(configFile), 0600) 28 | if err != nil { 29 | log.Fatal(err) 30 | } 31 | 32 | dumpFile("Dockerfile", dockerfile) 33 | dumpFile("docker-compose.yml", dockerComposeFile) 34 | } 35 | -------------------------------------------------------------------------------- /internal/backupnode/config.yml: -------------------------------------------------------------------------------- 1 | # Directory where the any-sync network configuration files are generated 2 | config_dir: configurations 3 | 4 | # IP of the host where the backup node will run. 5 | # Note that this IP must be accessible by your devices, it MUST NOT be a docker IP. 6 | # It can be a public IP or an IP from a LAN in which your devices are. 7 | host_ip: 192.168.1.1 8 | 9 | # Credentials for the minio service. 10 | minio_user: minio 11 | minio_password: a_strong_password 12 | 13 | # Credentials for the mongo service. 14 | mongo_user: mongo 15 | mongo_password: another_strong_password -------------------------------------------------------------------------------- /internal/backupnode/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | minio: 5 | image: quay.io/minio/minio 6 | command: server --console-address ":9001" /data 7 | ports: 8 | - 9000:9000 9 | - 9001:9001 10 | volumes: 11 | - s3:/data 12 | restart: unless-stopped 13 | env_file: 14 | - backupnode.env 15 | 16 | mongo: 17 | image: mongo:4.4 18 | volumes: 19 | - mongodb:/data/db 20 | ports: [] 21 | # - "27017:27017" 22 | restart: unless-stopped 23 | environment: 24 | - MONGO_INITDB_DATABASE=coordinator 25 | env_file: 26 | - backupnode.env 27 | 28 | redis: 29 | image: redis 30 | ports: [] 31 | # - "6379:6379" 32 | 33 | coordinator-node: 34 | build: 35 | context: . 36 | target: any-sync-coordinator 37 | ports: 38 | - "4830:4830" 39 | restart: unless-stopped 40 | volumes: 41 | - ./configurations/coordinator.yml:/etc/anytype/coordinator.yml 42 | 43 | sync-node: 44 | build: 45 | context: . 46 | target: any-sync-node 47 | ports: 48 | - "4430:4430" 49 | restart: unless-stopped 50 | volumes: 51 | - ./configurations/sync_1.yml:/etc/anytype/sync_1.yml 52 | 53 | file-node: 54 | build: 55 | context: . 56 | target: any-sync-filenode 57 | ports: 58 | - "4730:4730" 59 | restart: unless-stopped 60 | volumes: 61 | - ./configurations/file_1.yml:/etc/anytype/file_1.yml 62 | 63 | volumes: 64 | s3: 65 | mongodb: 66 | -------------------------------------------------------------------------------- /internal/backupnode/netconf.go: -------------------------------------------------------------------------------- 1 | package backupnode 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "path/filepath" 8 | 9 | "github.com/anyproto/any-sync-tools/any-sync-network/cmd" 10 | "gopkg.in/yaml.v3" 11 | ) 12 | 13 | type Config struct { 14 | HostIP string `yaml:"host_ip"` 15 | ConfigDir string `yaml:"config_dir"` 16 | 17 | MinioUser string `yaml:"minio_user"` 18 | MinioPassword string `yaml:"minio_password"` 19 | 20 | MongoUser string `yaml:"mongo_user"` 21 | MongoPassword string `yaml:"mongo_password"` 22 | } 23 | 24 | func readConfig(filePath string, cfgPtr any) { 25 | configFile, err := os.OpenFile(filePath, os.O_RDONLY, 0600) 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | defer configFile.Close() 30 | 31 | err = yaml.NewDecoder(configFile).Decode(cfgPtr) 32 | if err != nil { 33 | log.Fatal(err) 34 | } 35 | } 36 | 37 | func writeConfig(filePath string, cfg any) { 38 | configFile, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY, 0600) 39 | if err != nil { 40 | log.Fatal(err) 41 | } 42 | defer configFile.Close() 43 | 44 | err = yaml.NewEncoder(configFile).Encode(cfg) 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | } 49 | 50 | func GenerateNetworkConfig(configFilePath string) { 51 | b, err := os.ReadFile(configFilePath) 52 | if err != nil { 53 | log.Fatal(err) 54 | } 55 | 56 | var cfg Config 57 | err = yaml.Unmarshal(b, &cfg) 58 | if err != nil { 59 | log.Fatal(err) 60 | } 61 | 62 | configurationsDir := cfg.ConfigDir 63 | 64 | err = os.RemoveAll(configurationsDir) 65 | if err != nil && !os.IsNotExist(err) { 66 | log.Fatal(err) 67 | } 68 | err = os.Mkdir(configurationsDir, 0700) 69 | if err != nil { 70 | log.Fatal(err) 71 | } 72 | 73 | cmd.CreateConfig(configurationsDir, true) 74 | 75 | coordinatorConfigPath := filepath.Join(configurationsDir, "coordinator.yml") 76 | syncNodeConfigPath := filepath.Join(configurationsDir, "sync_1.yml") 77 | fileNodeConfigPath := filepath.Join(configurationsDir, "file_1.yml") 78 | heartConfigPath := filepath.Join(configurationsDir, "heart.yml") 79 | 80 | coordinatorConfig := cmd.CoordinatorNodeConfig{} 81 | readConfig(coordinatorConfigPath, &coordinatorConfig) 82 | syncNodeConfig := cmd.SyncNodeConfig{} 83 | readConfig(syncNodeConfigPath, &syncNodeConfig) 84 | fileNodeConfig := cmd.FileNodeConfig{} 85 | readConfig(fileNodeConfigPath, &fileNodeConfig) 86 | heartConfig := cmd.HeartConfig{} 87 | readConfig(heartConfigPath, &heartConfig) 88 | 89 | coordinatorAddr := fmt.Sprintf("%s:4830", cfg.HostIP) 90 | fileNodeAddr := fmt.Sprintf("%s:4730", cfg.HostIP) 91 | syncNodeAddr := fmt.Sprintf("%s:4430", cfg.HostIP) 92 | coordinatorConfig.Yamux.ListenAddrs[0] = "0.0.0.0:4830" 93 | coordinatorConfig.Network.Nodes[0].Addresses[0] = coordinatorAddr 94 | coordinatorConfig.Network.Nodes[1].Addresses[0] = syncNodeAddr 95 | coordinatorConfig.Network.Nodes[2].Addresses[0] = fileNodeAddr 96 | coordinatorConfig.Mongo.Connect = fmt.Sprintf("mongodb://%s:%s@mongo:27017", cfg.MongoUser, cfg.MongoPassword) 97 | 98 | syncNodeConfig.Yamux.ListenAddrs[0] = "0.0.0.0:4430" 99 | syncNodeConfig.Network.Nodes[0].Addresses[0] = coordinatorAddr 100 | syncNodeConfig.Network.Nodes[1].Addresses[0] = syncNodeAddr 101 | syncNodeConfig.Network.Nodes[2].Addresses[0] = fileNodeAddr 102 | 103 | fileNodeConfig.Yamux.ListenAddrs[0] = "0.0.0.0:4730" 104 | fileNodeConfig.Network.Nodes[0].Addresses[0] = coordinatorAddr 105 | fileNodeConfig.Network.Nodes[1].Addresses[0] = syncNodeAddr 106 | fileNodeConfig.Network.Nodes[2].Addresses[0] = fileNodeAddr 107 | fileNodeConfig.S3Store.Endpoint = "http://minio:9000/" 108 | fileNodeConfig.S3Store.Credentials.AccessKey = cfg.MinioUser 109 | fileNodeConfig.S3Store.Credentials.SecretKey = cfg.MinioPassword 110 | fileNodeConfig.S3Store.ForcePathStyle = true 111 | fileNodeConfig.Redis.URL = "redis://redis:6379/?dial_timeout=3&db=1&read_timeout=6s&max_retries=2" 112 | 113 | heartConfig.Nodes[0].Addresses[0] = fmt.Sprintf("%s:4830", cfg.HostIP) 114 | heartConfig.Nodes[1].Addresses[0] = fmt.Sprintf("%s:4430", cfg.HostIP) 115 | heartConfig.Nodes[2].Addresses[0] = fmt.Sprintf("%s:4730", cfg.HostIP) 116 | 117 | writeConfig(coordinatorConfigPath, coordinatorConfig) 118 | writeConfig(syncNodeConfigPath, syncNodeConfig) 119 | writeConfig(fileNodeConfigPath, fileNodeConfig) 120 | writeConfig(heartConfigPath, heartConfig) 121 | } 122 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/clems4ever/anytype-backup-node/internal/backupnode" 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | var configPathFlag string 11 | 12 | var defaultConfigPath = "config.yml" 13 | 14 | var rootCmd = cobra.Command{ 15 | Use: "anytype-backup-node", 16 | Short: "Start an anytype backup node", 17 | } 18 | 19 | var manualCmd = cobra.Command{ 20 | Use: "manual", 21 | Short: "Some commands that can be run manually if necessary.", 22 | Long: "Some commands that can be run manually if you know what you are doing, otherwise let the bootstrap command handle it for you.", 23 | } 24 | 25 | var initCmd = cobra.Command{ 26 | Use: "init", 27 | Short: "Generate a default configuration file that can be edited before bootstraping the infrastructure", 28 | Run: func(cmd *cobra.Command, args []string) { 29 | backupnode.Init() 30 | }, 31 | } 32 | 33 | var generateNetconfCmd = cobra.Command{ 34 | Use: "generate", 35 | Short: "Generate the configuration of an anytype backup node", 36 | Long: "Generate the configuration of an anytype backup node." + 37 | "This is only useful if you want to manually generate the configuration, " + 38 | "otherwise you can let the bootstrap command do it for you.", 39 | Run: func(cmd *cobra.Command, args []string) { 40 | backupnode.GenerateConfig(configPathFlag) 41 | }, 42 | } 43 | 44 | var bootstrapNodeCmd = cobra.Command{ 45 | Use: "bootstrap", 46 | Short: "Bootstrap a backup node after you have generated a config file with the init command", 47 | Long: "Bootstrap a backup node from the configuration file", 48 | Run: func(cmd *cobra.Command, args []string) { 49 | backupnode.Bootstrap(cmd.Context(), configPathFlag) 50 | }, 51 | } 52 | 53 | var configureCmd = cobra.Command{ 54 | Use: "configure", 55 | Short: "Configure the infrastructure after it has been spawned", 56 | Long: "Configure the infrastructure after it has been spawned. " + 57 | "This is only useful if you have to do it manually, otherwise you can let " + 58 | "the bootstrap command handle it for you.", 59 | Run: func(cmd *cobra.Command, args []string) { 60 | backupnode.Initialize(cmd.Context(), configPathFlag) 61 | }, 62 | } 63 | 64 | func main() { 65 | rootCmd.AddCommand(&initCmd) 66 | rootCmd.AddCommand(&manualCmd) 67 | 68 | generateNetconfCmd.Flags().StringVarP(&configPathFlag, "config", "c", defaultConfigPath, "path to the config file") 69 | manualCmd.AddCommand(&generateNetconfCmd) 70 | 71 | bootstrapNodeCmd.Flags().StringVarP(&configPathFlag, "config", "c", defaultConfigPath, "path to the config file") 72 | rootCmd.AddCommand(&bootstrapNodeCmd) 73 | 74 | configureCmd.Flags().StringVarP(&configPathFlag, "config", "c", defaultConfigPath, "path to the config file") 75 | manualCmd.AddCommand(&configureCmd) 76 | 77 | err := rootCmd.Execute() 78 | if err != nil { 79 | log.Fatal(err) 80 | } 81 | } 82 | --------------------------------------------------------------------------------