David Haukeness
3 years ago
3 changed files with 139 additions and 0 deletions
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
module git.hugfreevikings.wtf/keybase/libkeybase |
||||
|
||||
go 1.16 |
||||
|
||||
require samhofi.us/x/keybase/v2 v2.1.1 // indirect |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
samhofi.us/x/keybase/v2 v2.1.1 h1:XPWrmdbJCrNcsW3sRuR6WuALYOZt7O+av0My6YoehqE= |
||||
samhofi.us/x/keybase/v2 v2.1.1/go.mod h1:lJivwhzMSV+WUg+XUbatszStjjFVcuLGl+xcQpqQ5GQ= |
@ -0,0 +1,132 @@
@@ -0,0 +1,132 @@
|
||||
package libkeybase |
||||
|
||||
import ( |
||||
"bufio" |
||||
"bytes" |
||||
"fmt" |
||||
"io" |
||||
"os/exec" |
||||
"time" |
||||
) |
||||
|
||||
// RunOptions holds... run... options...
|
||||
type RunOptions struct { |
||||
KeybaseLoction string |
||||
HomeDir string |
||||
Username string |
||||
PaperKey string |
||||
EnableTyping bool |
||||
BotLiteMode bool |
||||
ChannelCapacity int |
||||
} |
||||
|
||||
// Location attempts to find the location of the keybase binary in the following order:
|
||||
// 1. What the user has specified as the location [user specified]
|
||||
// 2. Looks up the binary location using exec.LookPath [default]
|
||||
// 3. Returns "keybase" and hopes its pathed on the users system [fallback]
|
||||
func (r RunOptions) Location() string { |
||||
if r.KeybaseLoction != "" { |
||||
return r.KeybaseLoction |
||||
} |
||||
path, err := exec.LookPath("keybase") |
||||
if err != nil { |
||||
fmt.Println("INFO: Could not detect keybase in path") |
||||
return "keybase" |
||||
} |
||||
return path |
||||
} |
||||
|
||||
// buildBaseCommand adds the homedirectory before the args, when required
|
||||
func (r RunOptions) buildBaseCommand(args ...string) []string { |
||||
var cmd []string |
||||
if r.HomeDir != "" { |
||||
cmd = append(cmd, "--home", r.HomeDir) |
||||
} |
||||
cmd = append(cmd, args...) |
||||
return cmd |
||||
} |
||||
|
||||
// apiPrimitive is re-used between ApiWriter and ApiReader
|
||||
type apiPrimitive struct { |
||||
cmd *exec.Cmd |
||||
opts RunOptions |
||||
input io.WriteCloser |
||||
output io.ReadCloser |
||||
Input chan string |
||||
Output chan string |
||||
stop bool |
||||
die chan bool |
||||
} |
||||
|
||||
// Stop halts the subprocess
|
||||
func (a apiPrimitive) Stop() { |
||||
a.cmd.Process.Kill() |
||||
a.stop = true |
||||
a.die <- true |
||||
} |
||||
|
||||
// Start begins the subprocess call
|
||||
func (a apiPrimitive) Start(args ...string) (err error) { |
||||
// build the base command (homedir and stuff) and add the args to it
|
||||
cmdStrings := a.opts.buildBaseCommand(args...) |
||||
// set up the command execution
|
||||
a.cmd = exec.Command(a.opts.Location(), cmdStrings...) |
||||
// grab the process stdin pipe
|
||||
keyIn, err := a.cmd.StdinPipe() |
||||
if err != nil { |
||||
return |
||||
} |
||||
// grab the process stdout pipe
|
||||
keyOut, err := a.cmd.StdoutPipe() |
||||
if err != nil { |
||||
return |
||||
} |
||||
// buffer the channels to communicate with this process
|
||||
a.Input = make(chan string, a.opts.ChannelCapacity) |
||||
a.Output = make(chan string, a.opts.ChannelCapacity) |
||||
// now we need to start a select where anything in the channel goes to stdin
|
||||
go func() { |
||||
select { |
||||
case msg := <-a.Input: |
||||
_, err = keyIn.Write([]byte(msg)) |
||||
if err != nil { |
||||
return |
||||
} |
||||
case <-a.die: |
||||
return |
||||
} |
||||
}() |
||||
// then we need to start a loop where anything in the output goes to the channel
|
||||
go func() { |
||||
r := bufio.NewReader(keyOut) |
||||
buf := bytes.NewBufferString("") |
||||
for !a.stop { |
||||
line, isPrefix, err := r.ReadLine() |
||||
if err != nil { |
||||
return |
||||
} |
||||
if isPrefix { |
||||
// if its not a complete line, write it to the buffer only so we loop again
|
||||
buf.Write(line) |
||||
} else { |
||||
// if the line is complete, write it to the buffer
|
||||
buf.Write(line) |
||||
// then write the entire buffer to the channel
|
||||
a.Output <- buf.String() |
||||
// then reset the buffer so it can be re-used
|
||||
buf.Reset() |
||||
} |
||||
} |
||||
}() |
||||
// if you've made it this far, return the IO channels
|
||||
return nil |
||||
} |
||||
|
||||
type apiWriter struct { |
||||
apiPrimitive |
||||
} |
||||
|
||||
// API is the basic primitive of the API, holding the actual application calls and pipes
|
||||
type API struct { |
||||
Timeout time.Duration |
||||
} |
Loading…
Reference in new issue