Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ go.work.sum
# .idea/
# .vscode/

timekeep.db
testbuild.sh
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ sudo systemctl daemon-reload
- Windows - Check for running processes on service start
- CLI - commands
- sorting for session history
- show active sessions
- show active sessions (✓)
- enhance ping for more service info

## Contributing & Issues
Expand Down
48 changes: 35 additions & 13 deletions cmd/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,19 +225,6 @@ func (s *CLIService) ResetStats(args []string, all bool) error {
return nil
}

// Formats a time.Duration value to display hours, minutes or seconds
func (s *CLIService) formatDuration(prefix string, duration time.Duration) {
if duration < time.Minute {
fmt.Printf("%s%d seconds\n", prefix, int(duration.Seconds()))
} else if duration < time.Hour {
fmt.Printf("%s%d minutes\n", prefix, int(duration.Minutes()))
} else {
hours := int(duration.Hours())
minutes := int(duration.Minutes()) % 60
fmt.Printf("%s%dh %dm\n", prefix, hours, minutes)
}
}

// Removes active session and session records for all programs
func (s *CLIService) ResetAllDatabase() error {
err := s.AsRepo.RemoveAllSessions(context.Background())
Expand Down Expand Up @@ -275,3 +262,38 @@ func (s *CLIService) ResetDatabaseForProgram(program string) error {

return nil
}

// Prints a list of currently active sessions being tracked by service
func (s *CLIService) GetActiveSessions() error {
activeSessions, err := s.AsRepo.GetAllActiveSessions(context.Background())
if err != nil {
return fmt.Errorf("error getting active sessions: %w", err)
}
if len(activeSessions) == 0 {
fmt.Println("No active sessions.")
return nil
}

fmt.Println("Active sessions: ")
for _, session := range activeSessions {
duration := time.Since(session.StartTime)
sessionDetails := fmt.Sprintf(" • %s - ", session.ProgramName)

s.formatDuration(sessionDetails, duration)
}

return nil
}

// Formats a time.Duration value to display hours, minutes or seconds
func (s *CLIService) formatDuration(prefix string, duration time.Duration) {
if duration < time.Minute {
fmt.Printf("%s%d seconds\n", prefix, int(duration.Seconds()))
} else if duration < time.Hour {
fmt.Printf("%s%d minutes\n", prefix, int(duration.Minutes()))
} else {
hours := int(duration.Hours())
minutes := int(duration.Minutes()) % 60
fmt.Printf("%s%dh %dm\n", prefix, hours, minutes)
}
}
13 changes: 12 additions & 1 deletion cmd/cli/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,5 +222,16 @@ func TestPingService(t *testing.T) {
}

err = s.PingService()
assert.Nil(t, err, "PingService should not err")

assert.Contains(t, err.Error(), "service not running")
}

func TestGetActiveSessions(t *testing.T) {
s, err := setupTestServiceWithPrograms(t, "notepad.exe", "code.exe")
if err != nil {
t.Fatalf("Failed to setup test service: %v", err)
}

err = s.GetActiveSessions()
assert.Nil(t, err, "GetActiveSessions should not err")
}
7 changes: 7 additions & 0 deletions cmd/cli/ping_unsupported.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build !windows && !linux

package main

func (s *CLIService) PingService() error {
return nil
}
2 changes: 1 addition & 1 deletion cmd/cli/ping_windows.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !linux
//go:build windows

package main

Expand Down
1 change: 1 addition & 0 deletions cmd/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func (s *CLIService) RootCmd() *cobra.Command {
rootCmd.AddCommand(s.refreshCmd())
rootCmd.AddCommand(s.resetStatsCmd())
rootCmd.AddCommand(s.pingServiceCmd())
rootCmd.AddCommand(s.getActiveSessionsCmd())

return rootCmd
}
Expand Down
12 changes: 12 additions & 0 deletions cmd/cli/timekeep.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,15 @@ func (s *CLIService) pingServiceCmd() *cobra.Command {
},
}
}

func (s *CLIService) getActiveSessionsCmd() *cobra.Command {
return &cobra.Command{
Use: "active",
Aliases: []string{"Active", "ACTIVE"},
Short: "Get list of current active sessions being tracked",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
return s.GetActiveSessions()
},
}
}
6 changes: 1 addition & 5 deletions cmd/service/internal/events/events_unsupported.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ import (
"github.com/jms-guy/timekeep/internal/repository"
)

func (e *EventController) MonitorProcesses(logger *log.Logger, s *sessions.SessionManager, pr repository.ProgramRepository, a repository.ActiveRepository, h repository.ActiveRepository, programs []string) {
return
}

func (e *EventController) startProcessMonitor(logger *log.Logger, programs []string) {
func (e *EventController) MonitorProcesses(logger *log.Logger, s *sessions.SessionManager, pr repository.ProgramRepository, a repository.ActiveRepository, h repository.HistoryRepository, programs []string) {
return
}

Expand Down
11 changes: 11 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,35 @@
- `add`
- Add a program to begin tracking. Add name of program's executable file name. May specify any number of programs to track in a single command, seperated by spaces in between
- `timekeep add notepad.exe`, `timekeep add notepad.exe code.exe chrome.exe`

- `rm`
- Remove a program from tracking list. May specify any number of programs to remove in a single command, seperated by spaces in between. Takes `--all` flag to clear program list completely
- `timekeep rm notepad.exe`, `timekeep rm --all`

- `ls`
- Lists programs being tracked by service
- `timekeep ls`

- `stats`
- Shows stats for currently tracked programs. Accepts program name as argument to show in-depth stats for that program, else shows basic stats for all programs
- `timekeep stats`, `timekeep stats notepad.exe`

- `active`
- Display list of current active sessions being tracked by service
- `timekeep active`

- `history`
- Shows session history for a given program
- `timekeep history notepad.exe`

- `refresh`
- Sends a manual refresh command to the service
- `timekeep refresh`

- `reset`
- Reset tracking stats for given programs. Accepts multiple arguments seperated by space. Takes `--all` flag to reset all stats
- `timekeep reset notepad.exe`, `timekeep reset --all`

- `ping`
- Gets current state of Timekeep service
- `timekeep ping`
27 changes: 27 additions & 0 deletions internal/database/active_sessions.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions internal/repository/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type ProgramRepository interface {
type ActiveRepository interface {
CreateActiveSession(ctx context.Context, arg database.CreateActiveSessionParams) error
GetActiveSession(ctx context.Context, programName string) (time.Time, error)
GetAllActiveSessions(ctx context.Context) ([]database.ActiveSession, error)
RemoveActiveSession(ctx context.Context, programName string) error
RemoveAllSessions(ctx context.Context) error
}
Expand Down Expand Up @@ -96,6 +97,11 @@ func (s *sqliteStore) GetActiveSession(ctx context.Context, programName string)
return result, err
}

func (s *sqliteStore) GetAllActiveSessions(ctx context.Context) ([]database.ActiveSession, error) {
result, err := s.db.GetAllActiveSessions(ctx)
return result, err
}

func (s *sqliteStore) RemoveActiveSession(ctx context.Context, programName string) error {
return s.db.RemoveActiveSession(ctx, programName)
}
Expand Down
3 changes: 3 additions & 0 deletions sql/queries/active_sessions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ VALUES (?, ?);
SELECT start_time FROM active_sessions
WHERE program_name = ?;

-- name: GetAllActiveSessions :many
SELECT * FROM active_sessions;

-- name: RemoveActiveSession :exec
DELETE FROM active_sessions
WHERE program_name = ?;
Expand Down