2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2017 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
32 "golang.org/x/crypto/blake2b"
35 func (ctx *Ctx) Tx(node *Node, pkt *Pkt, nice uint8, size, minSize int64, src io.Reader) (*Node, error) {
36 tmp, err := ctx.NewTmpFileWHash()
40 hops := make([]*Node, 0, 1+len(node.Via))
41 hops = append(hops, node)
43 for i := len(node.Via); i > 0; i-- {
44 lastNode = ctx.Neigh[*node.Via[i-1]]
45 hops = append(hops, lastNode)
47 padSize := minSize - size - int64(len(hops))*(PktOverhead+PktEncOverhead)
51 errs := make(chan error)
53 pipeR, pipeW := io.Pipe()
54 go func(size int64, src io.Reader, dst io.WriteCloser) {
57 "nice": strconv.Itoa(int(nice)),
58 "size": strconv.FormatInt(size, 10),
60 errs <- PktEncWrite(ctx.Self, hops[0], pkt, nice, size, padSize, src, dst)
62 }(curSize, src, pipeW)
65 var pipeRPrev io.Reader
66 for i := 1; i < len(hops); i++ {
70 PathLen: blake2b.Size256,
71 Path: new([MaxPathSize]byte),
73 copy(pktTrans.Path[:], hops[i-1].Id[:])
74 curSize += PktOverhead + PktEncOverhead
76 pipeR, pipeW = io.Pipe()
77 go func(node *Node, pkt *Pkt, size int64, src io.Reader, dst io.WriteCloser) {
80 "nice": strconv.Itoa(int(nice)),
81 "size": strconv.FormatInt(size, 10),
83 errs <- PktEncWrite(ctx.Self, node, pkt, nice, size, 0, src, dst)
85 }(hops[i], &pktTrans, curSize, pipeRPrev, pipeW)
88 _, err := io.Copy(tmp.W, pipeR)
91 for i := 0; i <= len(hops); i++ {
98 nodePath := filepath.Join(ctx.Spool, lastNode.Id.String())
99 err = tmp.Commit(filepath.Join(nodePath, string(TTx)))
100 os.Symlink(nodePath, filepath.Join(ctx.Spool, lastNode.Name))
104 func (ctx *Ctx) TxFile(node *Node, nice uint8, srcPath, dstPath string, minSize int64) error {
106 dstPath = filepath.Base(srcPath)
108 dstPath = filepath.Clean(dstPath)
109 if filepath.IsAbs(dstPath) {
110 return errors.New("Relative destination path required")
112 pkt, err := NewPkt(PktTypeFile, dstPath)
116 src, err := os.Open(srcPath)
121 srcStat, err := src.Stat()
125 _, err = ctx.Tx(node, pkt, nice, srcStat.Size(), minSize, bufio.NewReader(src))
130 "nice": strconv.Itoa(int(nice)),
133 "size": strconv.FormatInt(srcStat.Size(), 10),
139 "nice": strconv.Itoa(int(nice)),
142 "size": strconv.FormatInt(srcStat.Size(), 10),
149 func (ctx *Ctx) TxFreq(node *Node, nice uint8, srcPath, dstPath string, minSize int64) error {
150 dstPath = filepath.Clean(dstPath)
151 if filepath.IsAbs(dstPath) {
152 return errors.New("Relative destination path required")
154 srcPath = filepath.Clean(srcPath)
155 if filepath.IsAbs(srcPath) {
156 return errors.New("Relative source path required")
158 pkt, err := NewPkt(PktTypeFreq, srcPath)
162 src := strings.NewReader(dstPath)
163 size := int64(src.Len())
164 _, err = ctx.Tx(node, pkt, nice, size, minSize, src)
169 "nice": strconv.Itoa(int(nice)),
177 "nice": strconv.Itoa(int(nice)),
186 func (ctx *Ctx) TxMail(node *Node, nice uint8, recipient string, body []byte, minSize int64) error {
187 pkt, err := NewPkt(PktTypeMail, recipient)
191 var compressed bytes.Buffer
192 compressor, err := zlib.NewWriterLevel(&compressed, zlib.BestCompression)
196 if _, err = io.Copy(compressor, bytes.NewReader(body)); err != nil {
200 size := int64(compressed.Len())
201 _, err = ctx.Tx(node, pkt, nice, size, minSize, &compressed)
206 "nice": strconv.Itoa(int(nice)),
208 "size": strconv.FormatInt(size, 10),
214 "nice": strconv.Itoa(int(nice)),
216 "size": strconv.FormatInt(size, 10),
223 func (ctx *Ctx) TxTrns(node *Node, nice uint8, size int64, src io.Reader) error {
227 "nice": strconv.Itoa(int(nice)),
228 "size": strconv.FormatInt(size, 10),
230 tmp, err := ctx.NewTmpFileWHash()
234 if _, err = io.Copy(tmp.W, src); err != nil {
237 nodePath := filepath.Join(ctx.Spool, node.Id.String())
238 err = tmp.Commit(filepath.Join(nodePath, string(TTx)))
243 "nice": strconv.Itoa(int(nice)),
244 "size": strconv.FormatInt(size, 10),
250 "nice": strconv.Itoa(int(nice)),
251 "size": strconv.FormatInt(size, 10),
255 os.Symlink(nodePath, filepath.Join(ctx.Spool, node.Name))