mirror of
https://github.com/postmannen/ctrl.git
synced 2025-01-05 20:09:16 +00:00
Transer of files initially works
This commit is contained in:
parent
49a88b83ce
commit
7c991ee3d5
3 changed files with 235 additions and 0 deletions
|
@ -70,6 +70,8 @@ type Configuration struct {
|
||||||
StartSubREQToFileAppend bool
|
StartSubREQToFileAppend bool
|
||||||
// Subscriber for writing to file
|
// Subscriber for writing to file
|
||||||
StartSubREQToFile bool
|
StartSubREQToFile bool
|
||||||
|
// Subscriber for reading files to copy
|
||||||
|
StartSubREQCopyFileFrom bool
|
||||||
// Subscriber for Echo Request
|
// Subscriber for Echo Request
|
||||||
StartSubREQPing bool
|
StartSubREQPing bool
|
||||||
// Subscriber for Echo Reply
|
// Subscriber for Echo Reply
|
||||||
|
@ -117,6 +119,7 @@ type ConfigurationFromFile struct {
|
||||||
StartSubREQHello *bool
|
StartSubREQHello *bool
|
||||||
StartSubREQToFileAppend *bool
|
StartSubREQToFileAppend *bool
|
||||||
StartSubREQToFile *bool
|
StartSubREQToFile *bool
|
||||||
|
StartSubREQCopyFileFrom *bool
|
||||||
StartSubREQPing *bool
|
StartSubREQPing *bool
|
||||||
StartSubREQPong *bool
|
StartSubREQPong *bool
|
||||||
StartSubREQCliCommand *bool
|
StartSubREQCliCommand *bool
|
||||||
|
@ -160,6 +163,7 @@ func newConfigurationDefaults() Configuration {
|
||||||
StartSubREQHello: true,
|
StartSubREQHello: true,
|
||||||
StartSubREQToFileAppend: true,
|
StartSubREQToFileAppend: true,
|
||||||
StartSubREQToFile: true,
|
StartSubREQToFile: true,
|
||||||
|
StartSubREQCopyFileFrom: true,
|
||||||
StartSubREQPing: true,
|
StartSubREQPing: true,
|
||||||
StartSubREQPong: true,
|
StartSubREQPong: true,
|
||||||
StartSubREQCliCommand: true,
|
StartSubREQCliCommand: true,
|
||||||
|
@ -298,6 +302,11 @@ func checkConfigValues(cf ConfigurationFromFile) Configuration {
|
||||||
} else {
|
} else {
|
||||||
conf.StartSubREQToFile = *cf.StartSubREQToFile
|
conf.StartSubREQToFile = *cf.StartSubREQToFile
|
||||||
}
|
}
|
||||||
|
if cf.StartSubREQCopyFileFrom == nil {
|
||||||
|
conf.StartSubREQCopyFileFrom = cd.StartSubREQCopyFileFrom
|
||||||
|
} else {
|
||||||
|
conf.StartSubREQCopyFileFrom = *cf.StartSubREQCopyFileFrom
|
||||||
|
}
|
||||||
if cf.StartSubREQPing == nil {
|
if cf.StartSubREQPing == nil {
|
||||||
conf.StartSubREQPing = cd.StartSubREQPing
|
conf.StartSubREQPing = cd.StartSubREQPing
|
||||||
} else {
|
} else {
|
||||||
|
@ -396,6 +405,7 @@ func (c *Configuration) CheckFlags() error {
|
||||||
flag.BoolVar(&c.StartSubREQHello, "startSubREQHello", fc.StartSubREQHello, "true/false")
|
flag.BoolVar(&c.StartSubREQHello, "startSubREQHello", fc.StartSubREQHello, "true/false")
|
||||||
flag.BoolVar(&c.StartSubREQToFileAppend, "startSubREQToFileAppend", fc.StartSubREQToFileAppend, "true/false")
|
flag.BoolVar(&c.StartSubREQToFileAppend, "startSubREQToFileAppend", fc.StartSubREQToFileAppend, "true/false")
|
||||||
flag.BoolVar(&c.StartSubREQToFile, "startSubREQToFile", fc.StartSubREQToFile, "true/false")
|
flag.BoolVar(&c.StartSubREQToFile, "startSubREQToFile", fc.StartSubREQToFile, "true/false")
|
||||||
|
flag.BoolVar(&c.StartSubREQCopyFileFrom, "startSubREQCopyFileFrom", fc.StartSubREQCopyFileFrom, "true/false")
|
||||||
flag.BoolVar(&c.StartSubREQPing, "startSubREQPing", fc.StartSubREQPing, "true/false")
|
flag.BoolVar(&c.StartSubREQPing, "startSubREQPing", fc.StartSubREQPing, "true/false")
|
||||||
flag.BoolVar(&c.StartSubREQPong, "startSubREQPong", fc.StartSubREQPong, "true/false")
|
flag.BoolVar(&c.StartSubREQPong, "startSubREQPong", fc.StartSubREQPong, "true/false")
|
||||||
flag.BoolVar(&c.StartSubREQCliCommand, "startSubREQCliCommand", fc.StartSubREQCliCommand, "true/false")
|
flag.BoolVar(&c.StartSubREQCliCommand, "startSubREQCliCommand", fc.StartSubREQCliCommand, "true/false")
|
||||||
|
|
13
processes.go
13
processes.go
|
@ -107,6 +107,11 @@ func (p *processes) Start(proc process) {
|
||||||
proc.startup.subREQToFile(proc)
|
proc.startup.subREQToFile(proc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start a subscriber for reading file to copy
|
||||||
|
if proc.configuration.StartSubREQCopyFileFrom {
|
||||||
|
proc.startup.subREQCopyFileFrom(proc)
|
||||||
|
}
|
||||||
|
|
||||||
// Start a subscriber for Hello messages
|
// Start a subscriber for Hello messages
|
||||||
if proc.configuration.StartSubREQHello {
|
if proc.configuration.StartSubREQHello {
|
||||||
proc.startup.subREQHello(proc)
|
proc.startup.subREQHello(proc)
|
||||||
|
@ -320,6 +325,14 @@ func (s startup) subREQToFile(p process) {
|
||||||
go proc.spawnWorker(p.processes, p.natsConn)
|
go proc.spawnWorker(p.processes, p.natsConn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s startup) subREQCopyFileFrom(p process) {
|
||||||
|
log.Printf("Starting copy file from subscriber: %#v\n", p.node)
|
||||||
|
sub := newSubject(REQCopyFileFrom, string(p.node))
|
||||||
|
proc := newProcess(p.ctx, s.metrics, p.natsConn, p.processes, p.toRingbufferCh, p.configuration, sub, p.errorCh, processKindSubscriber, nil)
|
||||||
|
|
||||||
|
go proc.spawnWorker(p.processes, p.natsConn)
|
||||||
|
}
|
||||||
|
|
||||||
func (s startup) subREQToFileAppend(p process) {
|
func (s startup) subREQToFileAppend(p process) {
|
||||||
log.Printf("Starting text logging subscriber: %#v\n", p.node)
|
log.Printf("Starting text logging subscriber: %#v\n", p.node)
|
||||||
sub := newSubject(REQToFileAppend, string(p.node))
|
sub := newSubject(REQToFileAppend, string(p.node))
|
||||||
|
|
212
requests.go
212
requests.go
|
@ -98,6 +98,10 @@ const (
|
||||||
// The data field is a slice of strings where the values of the
|
// The data field is a slice of strings where the values of the
|
||||||
// slice will be written to the file.
|
// slice will be written to the file.
|
||||||
REQToFile Method = "REQToFile"
|
REQToFile Method = "REQToFile"
|
||||||
|
// Read the source file to be copied to some node.
|
||||||
|
REQCopyFileFrom Method = "REQCopyFileFrom"
|
||||||
|
// Write the destination copied to some node.
|
||||||
|
REQCopyFileTo Method = "REQCopyFileTo"
|
||||||
// Send Hello I'm here message.
|
// Send Hello I'm here message.
|
||||||
REQHello Method = "REQHello"
|
REQHello Method = "REQHello"
|
||||||
// Error log methods to centralError node.
|
// Error log methods to centralError node.
|
||||||
|
@ -159,6 +163,12 @@ func (m Method) GetMethodsAvailable() MethodsAvailable {
|
||||||
REQToFile: methodREQToFile{
|
REQToFile: methodREQToFile{
|
||||||
commandOrEvent: EventACK,
|
commandOrEvent: EventACK,
|
||||||
},
|
},
|
||||||
|
REQCopyFileFrom: methodREQCopyFileFrom{
|
||||||
|
commandOrEvent: EventACK,
|
||||||
|
},
|
||||||
|
REQCopyFileTo: methodREQCopyFileTo{
|
||||||
|
commandOrEvent: EventACK,
|
||||||
|
},
|
||||||
REQHello: methodREQHello{
|
REQHello: methodREQHello{
|
||||||
commandOrEvent: EventNACK,
|
commandOrEvent: EventNACK,
|
||||||
},
|
},
|
||||||
|
@ -642,6 +652,208 @@ func (m methodREQToFile) handler(proc process, message Message, node string) ([]
|
||||||
return ackMsg, nil
|
return ackMsg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
|
||||||
|
type methodREQCopyFileFrom struct {
|
||||||
|
commandOrEvent CommandOrEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m methodREQCopyFileFrom) getKind() CommandOrEvent {
|
||||||
|
return m.commandOrEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle writing to a file. Will truncate any existing data if the file did already
|
||||||
|
// exist.
|
||||||
|
func (m methodREQCopyFileFrom) handler(proc process, message Message, node string) ([]byte, error) {
|
||||||
|
|
||||||
|
proc.processes.wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer proc.processes.wg.Done()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(message.MethodArgs) < 3:
|
||||||
|
er := fmt.Errorf("error: methodREQCliCommand: got <3 number methodArgs: want srcfilePath,dstNode,dstFilePath")
|
||||||
|
sendErrorLogMessage(proc.configuration, proc.processes.metrics, proc.toRingbufferCh, proc.node, er)
|
||||||
|
log.Printf("%v\n", er)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
SrcFilePath := message.MethodArgs[0]
|
||||||
|
DstNode := message.MethodArgs[1]
|
||||||
|
DstFilePath := message.MethodArgs[2]
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(proc.ctx, time.Second*2)
|
||||||
|
|
||||||
|
outCh := make(chan []byte)
|
||||||
|
errCh := make(chan error)
|
||||||
|
|
||||||
|
// Read the file, and put the result on the out channel to be sent when done reading.
|
||||||
|
proc.processes.wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
fmt.Printf(" * DEBUG: beginning of read file go routine\n")
|
||||||
|
defer proc.processes.wg.Done()
|
||||||
|
|
||||||
|
const natsMaxMsgSize = 1000000
|
||||||
|
|
||||||
|
fi, err := os.Stat(SrcFilePath)
|
||||||
|
|
||||||
|
// Check if the src file exists, and that it is not bigger than
|
||||||
|
// the default limit used by nats which is 1MB.
|
||||||
|
switch {
|
||||||
|
case os.IsNotExist(err):
|
||||||
|
errCh <- fmt.Errorf("error: methodREQCopyFile: src file not found: %v", SrcFilePath)
|
||||||
|
return
|
||||||
|
case fi.Size() > natsMaxMsgSize:
|
||||||
|
errCh <- fmt.Errorf("error: methodREQCopyFile: src file to big. max size: %v", natsMaxMsgSize)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fh, err := os.Open(SrcFilePath)
|
||||||
|
if err != nil {
|
||||||
|
errCh <- fmt.Errorf("error: methodREQCopyFile: failed to open file: %v, %v", SrcFilePath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(" * DEBUG: before io.ReadAll\n")
|
||||||
|
|
||||||
|
b, err := io.ReadAll(fh)
|
||||||
|
if err != nil {
|
||||||
|
errCh <- fmt.Errorf("error: methodREQCopyFile: failed to read file: %v, %v", SrcFilePath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(" * DEBUG: after io.ReadAll: b contains: %v\n", string(b))
|
||||||
|
|
||||||
|
select {
|
||||||
|
case outCh <- b:
|
||||||
|
fmt.Printf(" * DEBUG: after io.ReadAll: outCh <- b\n")
|
||||||
|
case <-ctx.Done():
|
||||||
|
fmt.Printf(" * DEBUG: after io.ReadAll: ctx.Done\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait here until we got the data to send, then create a new message
|
||||||
|
// and send it.
|
||||||
|
// Also checking the ctx.Done which calls Cancel will allow us to
|
||||||
|
// kill all started go routines started by this message.
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
fmt.Printf(" ** DEBUG: got ctx.Done\n")
|
||||||
|
cancel()
|
||||||
|
er := fmt.Errorf("error: methodREQCopyFile: got <-ctx.Done(): %v", message.MethodArgs)
|
||||||
|
sendErrorLogMessage(proc.configuration, proc.processes.metrics, proc.toRingbufferCh, proc.node, er)
|
||||||
|
|
||||||
|
return
|
||||||
|
case er := <-errCh:
|
||||||
|
fmt.Printf(" ** DEBUG: received on errCh: <-errCh\n")
|
||||||
|
sendErrorLogMessage(proc.configuration, proc.processes.metrics, proc.toRingbufferCh, proc.node, er)
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
return
|
||||||
|
case out := <-outCh:
|
||||||
|
fmt.Printf(" ** DEBUG: got data on out channel: case out:=<-outCh\n")
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
dstDir := filepath.Dir(DstFilePath)
|
||||||
|
dstFile := filepath.Base(DstFilePath)
|
||||||
|
|
||||||
|
// Prepare for sending a new message with the output
|
||||||
|
// TODO: Maybe changing the type of Message.Data to []byte ?
|
||||||
|
|
||||||
|
// Copy the original message to get the defaults for timeouts etc,
|
||||||
|
// and set new values for fields to change.
|
||||||
|
msg := message
|
||||||
|
msg.ToNode = Node(DstNode)
|
||||||
|
msg.Method = REQToFile
|
||||||
|
// TODO: msg.Method = REQCopyFileTo
|
||||||
|
msg.Data = []string{string(out)}
|
||||||
|
msg.Directory = dstDir
|
||||||
|
msg.FileName = dstFile
|
||||||
|
|
||||||
|
// Create SAM and put the message on the send new message channel.
|
||||||
|
|
||||||
|
sam, err := newSubjectAndMessage(msg)
|
||||||
|
if err != nil {
|
||||||
|
er := fmt.Errorf("error: newSubjectAndMessage : %v, message: %v", err, message)
|
||||||
|
sendErrorLogMessage(proc.configuration, proc.processes.metrics, proc.toRingbufferCh, proc.node, er)
|
||||||
|
log.Printf("%v\n", er)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(" * DEBUG: sending SAM: %#v\n", sam)
|
||||||
|
|
||||||
|
proc.toRingbufferCh <- []subjectAndMessage{sam}
|
||||||
|
|
||||||
|
// TODO: Should we also send a reply message with the result back
|
||||||
|
// to where the message originated ?
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
|
ackMsg := []byte("confirmed from: " + node + ": " + fmt.Sprint(message.ID))
|
||||||
|
return ackMsg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
|
||||||
|
type methodREQCopyFileTo struct {
|
||||||
|
commandOrEvent CommandOrEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m methodREQCopyFileTo) getKind() CommandOrEvent {
|
||||||
|
return m.commandOrEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle writing to a file. Will truncate any existing data if the file did already
|
||||||
|
// exist.
|
||||||
|
// Same as the REQToFile, but this requst type don't use the default data folder path
|
||||||
|
// for where to store files or add information about node names.
|
||||||
|
func (m methodREQCopyFileTo) handler(proc process, message Message, node string) ([]byte, error) {
|
||||||
|
|
||||||
|
// If it was a request type message we want to check what the initial messages
|
||||||
|
// method, so we can use that in creating the file name to store the data.
|
||||||
|
fileName, folderTree := message.FileName, message.Directory
|
||||||
|
|
||||||
|
// Check if folder structure exist, if not create it.
|
||||||
|
if _, err := os.Stat(folderTree); os.IsNotExist(err) {
|
||||||
|
err := os.MkdirAll(folderTree, 0700)
|
||||||
|
if err != nil {
|
||||||
|
er := fmt.Errorf("error: methodREQToFile failed to create toFile directory tree: subject:%v, folderTree: %v, %v", proc.subject, folderTree, err)
|
||||||
|
sendErrorLogMessage(proc.configuration, proc.processes.metrics, proc.toRingbufferCh, proc.node, er)
|
||||||
|
log.Printf("%v\n", er)
|
||||||
|
|
||||||
|
return nil, er
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("info: Creating subscribers data folder at %v\n", folderTree)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open file and write data.
|
||||||
|
file := filepath.Join(folderTree, fileName)
|
||||||
|
f, err := os.OpenFile(file, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0755)
|
||||||
|
if err != nil {
|
||||||
|
er := fmt.Errorf("error: methodREQToFile.handler: failed to open file, check that you've specified a value for fileName in the message: directory: %v, fileName: %v, %v", message.Directory, message.FileName, err)
|
||||||
|
sendErrorLogMessage(proc.configuration, proc.processes.metrics, proc.toRingbufferCh, proc.node, er)
|
||||||
|
log.Printf("%v\n", er)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
for _, d := range message.Data {
|
||||||
|
_, err := f.Write([]byte(d))
|
||||||
|
f.Sync()
|
||||||
|
if err != nil {
|
||||||
|
er := fmt.Errorf("error: methodEventTextLogging.handler: failed to write to file: file: %v, %v", file, err)
|
||||||
|
sendErrorLogMessage(proc.configuration, proc.processes.metrics, proc.toRingbufferCh, proc.node, er)
|
||||||
|
log.Printf("%v\n", er)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ackMsg := []byte("confirmed from: " + node + ": " + fmt.Sprint(message.ID))
|
||||||
|
return ackMsg, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ----
|
// ----
|
||||||
type methodREQHello struct {
|
type methodREQHello struct {
|
||||||
commandOrEvent CommandOrEvent
|
commandOrEvent CommandOrEvent
|
||||||
|
|
Loading…
Reference in a new issue