Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/websocket #8

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 57 additions & 7 deletions audioslave.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,47 @@ package audioslave

import (
"context"
"encoding/json"
"fmt"
"github.com/bevzzz/audioslave/internal/keyboard"
"github.com/bevzzz/audioslave/internal/volume"
"github.com/bevzzz/audioslave/pkg/algorithms"
"github.com/bevzzz/audioslave/pkg/config"
"log"
)

type AudioSlave struct {
KeystrokeCounter keyboard.KeystrokeCounter
VolumeController volume.VolumeController
Config config.Application
KeystrokeCounter keyboard.KeystrokeCounter
VolumeController volume.VolumeController
Config *config.Application
ReloadConfigChannel chan bool
PauseApplicationChannel chan bool
}

// Start - starts the audioslave
func (s AudioSlave) Start(ctx context.Context) error {
func (s *AudioSlave) Start(ctx context.Context) error {
s.HandleConfig()
s.PauseApplicationChannel = make(chan bool)
s.ReloadConfigChannel = make(chan bool)
countStrokes := s.KeystrokeCounter.Count(keyboard.NewDefaultTicker(s.Config.Config.Interval))
output := volume.NewOutput(s.Config.Config.Window, s.Config.Config.Interval,
s.Config.Config.AverageCpm, s.VolumeController, s.Config.Config.MinVolume)
s.HandleConfig()
for {
pause := false
select {
case <-ctx.Done():
return nil
case pause = <-s.PauseApplicationChannel:
// pause application
case <-s.ReloadConfigChannel:
// reload config
s.HandleConfig()
countStrokes = s.KeystrokeCounter.Count(keyboard.NewDefaultTicker(s.Config.Config.Interval))
output = volume.NewOutput(s.Config.Config.Window, s.Config.Config.Interval,
s.Config.Config.AverageCpm, s.VolumeController, s.Config.Config.MinVolume)
default:
}
if !pause {
n, ok := <-countStrokes
if !ok {
output.Reset()
Expand All @@ -37,7 +54,7 @@ func (s AudioSlave) Start(ctx context.Context) error {
}

// HandleConfig - handles the reading and saving of the config
func (s AudioSlave) HandleConfig() {
func (s *AudioSlave) HandleConfig() {
err := s.Config.Read()
if err != nil && s.Config.Config.Verbose {
log.Println("No config found")
Expand All @@ -57,7 +74,40 @@ func (s AudioSlave) HandleConfig() {
}

// Stop - stops the audioslave
func (s AudioSlave) Stop() {
func (s *AudioSlave) Stop() {
s.KeystrokeCounter.Stop()

}

// ChangeAlg - changes algorithm
func (s *AudioSlave) ChangeAlg(name string, data any, increase bool, reduce bool) error {
newAlgo := algorithms.AlgorithmByName(name)
dataRaw, err := json.Marshal(&data)
if err != nil {
return err
}
err = json.Unmarshal(dataRaw, &newAlgo)
if err != nil {
return err
}
if increase {
s.Config.IncreaseAlg = newAlgo
}
if reduce {
s.Config.ReduceAlg = newAlgo
}
s.Config.Write()
return nil
}

func (s *AudioSlave) Pause() {
s.PauseApplicationChannel <- true
}

func (s *AudioSlave) Resume() {
s.PauseApplicationChannel <- false
}

func (s *AudioSlave) ReloadConfig() {
s.ReloadConfigChannel <- true
}
19 changes: 16 additions & 3 deletions cmd/audioslave/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/bevzzz/audioslave/internal/util"
"github.com/bevzzz/audioslave/internal/volume"
"github.com/bevzzz/audioslave/pkg/algorithms"
"github.com/bevzzz/audioslave/pkg/api/websocket"
"github.com/bevzzz/audioslave/pkg/config"
"log"
"os"
Expand All @@ -22,10 +23,10 @@ func main() {
}
ctx, cancel := context.WithCancel(context.Background())

as := audioslave.AudioSlave{
as := &audioslave.AudioSlave{
KeystrokeCounter: keyboard.NewKeystrokeCounter(),
VolumeController: &volume.ItchynyVolumeController{},
Config: config.Application{
Config: &config.Application{
Config: *conf,
// Default algs
ReduceAlg: &algorithms.Linear{
Expand All @@ -50,7 +51,19 @@ func main() {
os.Exit(0)
}()
log.Println("Starting application...")
err := as.Start(ctx)
w := websocket.Websocket{
Application: as,
Port: "10001",
}
var err error
switch conf.Mode {
case "cli":
err = as.Start(ctx)
case "websocket":
err = w.Start(ctx)
default:
log.Fatalf("mode %s not found", conf.Mode)
}
if err != nil {
log.Fatal(err)
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.18

require (
github.com/TheTitanrain/w32 v0.0.0-20200114052255-2654d97dbd3d
github.com/gorilla/websocket v1.5.0
github.com/itchyny/volume-go v0.2.1
)

Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
github.com/MarinX/keylogger v0.0.0-20210528193429-a54d7834cc1a h1:ItKXWegGGThcahUf+ylKFa5pwqkRJofaOyeGdzwO2mM=
github.com/MarinX/keylogger v0.0.0-20210528193429-a54d7834cc1a/go.mod h1:aKzZ7D15UvH5LboXkeLmcNi+s/f805vUfB+BfW1fqd4=
github.com/TheTitanrain/w32 v0.0.0-20200114052255-2654d97dbd3d h1:2xp1BQbqcDDaikHnASWpVZRjibOxu7y9LhAv04whugI=
github.com/TheTitanrain/w32 v0.0.0-20200114052255-2654d97dbd3d/go.mod h1:peYoMncQljjNS6tZwI9WVyQB3qZS6u79/N3mBOcnd3I=
github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 h1:XBBHcIb256gUJtLmY22n99HaZTz+r2Z51xUPi01m3wg=
github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203/go.mod h1:E1jcSv8FaEny+OP/5k9UxZVw9YFWGj7eI4KR/iOBqCg=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/itchyny/volume-go v0.2.1 h1:NiVdnIp3dyCBnygQoBLV9ecAk7Vk4KHfiZFJGvCCIm0=
github.com/itchyny/volume-go v0.2.1/go.mod h1:YdvjyTIcPXyGcckaIHTfga+ItdhGZQoWhzOORajlkkE=
github.com/moutend/go-wca v0.2.0 h1:AEzY6ltC5zPCldKyMYdyXv3TaLqwxSW1TIradqNqRpU=
Expand Down
2 changes: 1 addition & 1 deletion internal/util/Util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package util

import "encoding/json"

func PrettyPrint(i interface{}) string {
func PrettyPrint(i any) string {
s, _ := json.MarshalIndent(i, "", "\t")
return string(s)
}
51 changes: 51 additions & 0 deletions pkg/api/websocket/Commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package websocket

import "fmt"

type CommandType string

var (
ACKCommand CommandType = "ACK"
ERRCommand CommandType = "ERR"
ALGCommand CommandType = "ALG"
STOPCommand CommandType = "STOP"
PAUSECommand CommandType = "PAUSE"
RESUMECommand CommandType = "RESUME"
RELOADCONFIGCommand CommandType = "RELOADCONFIG"
)

var (
ACK = Command{
Type: ACKCommand,
Payload: nil,
}
ERR = Command{
Type: ERRCommand,
Payload: nil,
}
)

type Command struct {
Type CommandType
Payload any
}

type commandAlg struct {
Type string
Reduce bool
Increase bool
Data any
}

// Decode - decodes the command
func (c *Command) Decode() error {
switch c.Type {
case ALGCommand:
_, ok := c.Payload.(commandAlg)
if !ok {
return fmt.Errorf("could not convert")
}
default:
}
return nil
}
122 changes: 122 additions & 0 deletions pkg/api/websocket/Websocket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package websocket

import (
"context"
"fmt"
"github.com/bevzzz/audioslave"
"github.com/gorilla/websocket"
"log"
"net/http"
)

type Websocket struct {
Application *audioslave.AudioSlave
Port string
Upgrader websocket.Upgrader
}

// Start - starts the websocket API and the application
func (w *Websocket) Start(ctx context.Context) error {
w.Upgrader = websocket.Upgrader{} // use default options
ctx, cancel := context.WithCancel(ctx)
go func() {
server := &http.Server{Addr: fmt.Sprintf("localhost:%s", w.Port),
Handler: w.socketHandler(ctx, cancel)}
err := server.ListenAndServe()
if err != nil {
log.Println(err)
w.Application.Stop()
}
}()
err := w.Application.Start(ctx)
if err != nil {
return err
}
return nil
}

// socketHandler - handler func for incoming request
func (w *Websocket) socketHandler(ctx context.Context, cancel context.CancelFunc) http.HandlerFunc {
return func(writer http.ResponseWriter, request *http.Request) {
conn, err := w.Upgrader.Upgrade(writer, request, nil)
if err != nil {
return
}
defer func() {
err := conn.Close()
log.Println(err)
cancel()
}()
for {
select {
case <-ctx.Done():
return
default:
}
command := &Command{}
// read json
err := conn.ReadJSON(command)
if err != nil {
log.Println(err)
conn.WriteJSON(&ERR)
continue
}
// write ack
err = conn.WriteJSON(&ACK)
if err != nil {
log.Println(err)
conn.WriteJSON(&ERR)
return
}
// decode command
err = command.Decode()
if err != nil {
log.Println(err)
conn.WriteJSON(&ERR)
continue
}
// process command
resp, err := w.ProcessCommand(*command, cancel)
if err != nil {
log.Println(err)
conn.WriteJSON(&ERR)
continue
}
// write resp. ack or data structure
err = conn.WriteJSON(&resp)
if err != nil {
log.Println(err)
conn.WriteJSON(&ERR)
return
}
}
}
}

// ProcessCommand - Process a command and returns a response
func (w *Websocket) ProcessCommand(command Command, cancel context.CancelFunc) (any, error) {
switch command.Type {
case STOPCommand:
w.Stop()
cancel()
case ALGCommand:
payload := command.Payload.(commandAlg)
err := w.Application.ChangeAlg(payload.Type, payload.Data, payload.Increase, payload.Reduce)
if err != nil {
return nil, err
}
case PAUSECommand:
w.Application.Pause()
case RESUMECommand:
w.Application.Resume()
case RELOADCONFIGCommand:
w.Application.ReloadConfig()
default:
}
return &ACK, nil
}

// Stop - stops the application underneath
func (w *Websocket) Stop() {
w.Application.Stop()
}
4 changes: 4 additions & 0 deletions pkg/config/Flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Config struct {
MaxVolume int
AverageCpm int
Interval, Window time.Duration
Mode string
Verbose bool
}

Expand All @@ -27,6 +28,7 @@ func ParseCommand() *Config {
Interval: time.Second,
Window: 10 * time.Second,
Verbose: false,
Mode: "websocket",
}

minVolume := flag.Int("min-volume", config.MinVolume, "set the minimum volume")
Expand All @@ -36,6 +38,7 @@ func ParseCommand() *Config {
window := flag.Duration("window", config.Window, "change output based on last N values")
path := flag.String("path", config.Path, "config path to safe and load")
verbose := flag.Bool("verbose", config.Verbose, "verbose logs")
mode := flag.String("mode", config.Mode, "application mode")

flag.Parse()

Expand All @@ -46,6 +49,7 @@ func ParseCommand() *Config {
config.Interval = *interval
config.Window = *window
config.Verbose = *verbose
config.Mode = *mode

return config
}