diff options
| author | Shulhan <ms@kilabit.info> | 2023-11-22 13:16:21 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2023-12-01 13:17:30 +0700 |
| commit | a73f0d5d0108e2e10d89f93c7867addbe073add9 (patch) | |
| tree | 042e69e2c1d10d836a006abca37417af02bba826 /exec_response.go | |
| parent | a9701f66c2e38a3a7f3d12deed6ebba5144e208e (diff) | |
| download | awwan-a73f0d5d0108e2e10d89f93c7867addbe073add9.tar.xz | |
all: refactoring HTTP endpoint for Execute
Previously, the Execute endpoint wait for command execution to finish.
In case the command takes longer than proxy or server write timeout, it
will return with an timeout error to client.
In this changes, we generate an execution ID for each request and return
it immediately.
The next commit will implement HTTP endpoint to fetch the latest status
and/or output by execution ID.
References: https://todo.sr.ht/~shulhan/awwan/5
Diffstat (limited to 'exec_response.go')
| -rw-r--r-- | exec_response.go | 79 |
1 files changed, 76 insertions, 3 deletions
diff --git a/exec_response.go b/exec_response.go index 661189f..9569aab 100644 --- a/exec_response.go +++ b/exec_response.go @@ -3,10 +3,83 @@ package awwan +import ( + "bytes" + "fmt" + "time" +) + // ExecResponse contains the request and output of command execution, from // ExecRequest. type ExecResponse struct { - *ExecRequest - Error string `json:"error"` - Output []byte `json:"output"` + // Copy of request. + + Mode string `json:"mode"` + Script string `json:"script"` + LineRange string `json:"line_range"` + + // ID of execution request that can be used to stream output or + // got get full status. + ID string `json:"id"` + + // BeginAt contains when the execution begin. + BeginAt string `json:"begin_at"` + + // EndAt contains when the execution finished. + EndAt string `json:"end_at"` + + Error string `json:"error"` + + Output []string `json:"output"` +} + +func newExecResponse(req *ExecRequest) (execRes *ExecResponse) { + var now = timeNow().UTC() + + execRes = &ExecResponse{ + Mode: req.Mode, + Script: req.Script, + LineRange: req.LineRange, + + ID: fmt.Sprintf(`%s:%s:%s:%d`, req.Mode, req.Script, req.LineRange, now.Unix()), + BeginAt: now.Format(time.RFC3339), + + Output: make([]string, 0, 8), + } + + // Use the ExecResponse itself as handler for output. + req.registerLogWriter(`response`, execRes) + + return execRes +} + +// Write convert the raw output from execution into multiline string, and +// push it to field Output. +func (execres *ExecResponse) Write(out []byte) (n int, err error) { + if len(out) == 0 { + return 0, nil + } + + var outlen = len(out) + if out[outlen-1] == '\n' { + out = out[:outlen-1] + outlen-- + } + + var ( + lines = bytes.Split(out, []byte{'\n'}) + line []byte + ) + for _, line = range lines { + execres.Output = append(execres.Output, string(line)) + } + + return outlen, nil +} + +func (execres *ExecResponse) end(execErr error) { + if execErr != nil { + execres.Error = execErr.Error() + } + execres.EndAt = timeNow().UTC().Format(time.RFC3339) } |
