Browse Source

Initial work

main
David Haukeness 3 years ago
parent
commit
32b8231da7
  1. 5
      go.mod
  2. 2
      go.sum
  3. 132
      libkeybase.go

5
go.mod

@ -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

2
go.sum

@ -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=

132
libkeybase.go

@ -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…
Cancel
Save