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 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 errs := make(chan error)
49 pipeR, pipeW := io.Pipe()
50 go func(size int64, src io.Reader, dst io.WriteCloser) {
53 "nice": strconv.Itoa(int(nice)),
54 "size": strconv.FormatInt(size, 10),
56 errs <- PktEncWrite(ctx.Self, hops[0], pkt, nice, size, src, dst)
58 }(curSize, src, pipeW)
60 var pipeRPrev io.Reader
61 for i := 1; i < len(hops); i++ {
65 PathLen: blake2b.Size256,
66 Path: new([MaxPathSize]byte),
68 copy(pktTrans.Path[:], hops[i-1].Id[:])
69 curSize += PktOverhead + PktEncOverhead
71 pipeR, pipeW = io.Pipe()
72 go func(node *Node, pkt *Pkt, size int64, src io.Reader, dst io.WriteCloser) {
75 "nice": strconv.Itoa(int(nice)),
76 "size": strconv.FormatInt(size, 10),
78 errs <- PktEncWrite(ctx.Self, node, pkt, nice, size, src, dst)
80 }(hops[i], &pktTrans, curSize, pipeRPrev, pipeW)
83 _, err := io.Copy(tmp.W, pipeR)
86 for i := 0; i <= len(hops); i++ {
93 nodePath := filepath.Join(ctx.Spool, lastNode.Id.String())
94 err = tmp.Commit(filepath.Join(nodePath, string(TTx)))
95 os.Symlink(nodePath, filepath.Join(ctx.Spool, lastNode.Name))
99 func (ctx *Ctx) TxFile(node *Node, nice uint8, srcPath, dstPath string) error {
101 dstPath = filepath.Base(srcPath)
103 dstPath = filepath.Clean(dstPath)
104 if filepath.IsAbs(dstPath) {
105 return errors.New("Relative destination path required")
107 pkt, err := NewPkt(PktTypeFile, dstPath)
111 src, err := os.Open(srcPath)
116 srcStat, err := src.Stat()
120 _, err = ctx.Tx(node, pkt, nice, srcStat.Size(), bufio.NewReader(src))
125 "nice": strconv.Itoa(int(nice)),
128 "size": strconv.FormatInt(srcStat.Size(), 10),
134 "nice": strconv.Itoa(int(nice)),
137 "size": strconv.FormatInt(srcStat.Size(), 10),
144 func (ctx *Ctx) TxFreq(node *Node, nice uint8, srcPath, dstPath string) error {
145 dstPath = filepath.Clean(dstPath)
146 if filepath.IsAbs(dstPath) {
147 return errors.New("Relative destination path required")
149 srcPath = filepath.Clean(srcPath)
150 if filepath.IsAbs(srcPath) {
151 return errors.New("Relative source path required")
153 pkt, err := NewPkt(PktTypeFreq, srcPath)
157 src := strings.NewReader(dstPath)
158 size := int64(src.Len())
159 _, err = ctx.Tx(node, pkt, nice, size, src)
164 "nice": strconv.Itoa(int(nice)),
172 "nice": strconv.Itoa(int(nice)),
181 func (ctx *Ctx) TxMail(node *Node, nice uint8, recipient string, body []byte) error {
182 pkt, err := NewPkt(PktTypeMail, recipient)
186 var compressed bytes.Buffer
187 compressor := zlib.NewWriter(&compressed)
188 if _, err = io.Copy(compressor, bytes.NewReader(body)); err != nil {
192 size := int64(compressed.Len())
193 _, err = ctx.Tx(node, pkt, nice, size, &compressed)
198 "nice": strconv.Itoa(int(nice)),
200 "size": strconv.FormatInt(size, 10),
206 "nice": strconv.Itoa(int(nice)),
208 "size": strconv.FormatInt(size, 10),
215 func (ctx *Ctx) TxTrns(node *Node, nice uint8, size int64, src io.Reader) error {
219 "nice": strconv.Itoa(int(nice)),
220 "size": strconv.FormatInt(size, 10),
222 tmp, err := ctx.NewTmpFileWHash()
226 if _, err = io.Copy(tmp.W, src); err != nil {
229 nodePath := filepath.Join(ctx.Spool, node.Id.String())
230 err = tmp.Commit(filepath.Join(nodePath, string(TTx)))
235 "nice": strconv.Itoa(int(nice)),
236 "size": strconv.FormatInt(size, 10),
242 "nice": strconv.Itoa(int(nice)),
243 "size": strconv.FormatInt(size, 10),
247 os.Symlink(nodePath, filepath.Join(ctx.Spool, node.Name))