mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-23 17:41:05 +01:00
fixing idlewatcher
This commit is contained in:
@@ -4,72 +4,101 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/events"
|
||||
docker_events "github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/sirupsen/logrus"
|
||||
D "github.com/yusing/go-proxy/docker"
|
||||
E "github.com/yusing/go-proxy/error"
|
||||
. "github.com/yusing/go-proxy/watcher/event"
|
||||
"github.com/yusing/go-proxy/watcher/events"
|
||||
)
|
||||
|
||||
type DockerWatcher struct {
|
||||
host string
|
||||
type (
|
||||
DockerWatcher struct {
|
||||
host string
|
||||
client D.Client
|
||||
logrus.FieldLogger
|
||||
}
|
||||
DockerListOptions = docker_events.ListOptions
|
||||
)
|
||||
|
||||
// https://docs.docker.com/reference/api/engine/version/v1.47/#tag/System/operation/SystemPingHead
|
||||
var (
|
||||
DockerFilterContainer = filters.Arg("type", string(docker_events.ContainerEventType))
|
||||
DockerFilterStart = filters.Arg("event", string(docker_events.ActionStart))
|
||||
DockerFilterStop = filters.Arg("event", string(docker_events.ActionStop))
|
||||
DockerFilterDie = filters.Arg("event", string(docker_events.ActionDie))
|
||||
DockerFilterKill = filters.Arg("event", string(docker_events.ActionKill))
|
||||
DockerFilterPause = filters.Arg("event", string(docker_events.ActionPause))
|
||||
DockerFilterUnpause = filters.Arg("event", string(docker_events.ActionUnPause))
|
||||
|
||||
NewDockerFilter = filters.NewArgs
|
||||
)
|
||||
|
||||
func DockerrFilterContainerName(name string) filters.KeyValuePair {
|
||||
return filters.Arg("container", name)
|
||||
}
|
||||
|
||||
func NewDockerWatcher(host string) *DockerWatcher {
|
||||
return &DockerWatcher{host: host}
|
||||
func NewDockerWatcher(host string) DockerWatcher {
|
||||
return DockerWatcher{host: host, FieldLogger: logrus.WithField("module", "docker_watcher")}
|
||||
}
|
||||
|
||||
func (w *DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan E.NestedError) {
|
||||
func NewDockerWatcherWithClient(client D.Client) DockerWatcher {
|
||||
return DockerWatcher{client: client, FieldLogger: logrus.WithField("module", "docker_watcher")}
|
||||
}
|
||||
|
||||
func (w DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan E.NestedError) {
|
||||
return w.EventsWithOptions(ctx, optionsWatchAll)
|
||||
}
|
||||
|
||||
func (w DockerWatcher) EventsWithOptions(ctx context.Context, options DockerListOptions) (<-chan Event, <-chan E.NestedError) {
|
||||
eventCh := make(chan Event)
|
||||
errCh := make(chan E.NestedError)
|
||||
started := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(eventCh)
|
||||
defer close(errCh)
|
||||
|
||||
var cl D.Client
|
||||
var err E.NestedError
|
||||
for range 3 {
|
||||
cl, err = D.ConnectClient(w.host)
|
||||
if err.NoError() {
|
||||
break
|
||||
if !w.client.Connected() {
|
||||
var err E.NestedError
|
||||
for range 3 {
|
||||
w.client, err = D.ConnectClient(w.host)
|
||||
if err != nil {
|
||||
defer w.client.Close()
|
||||
break
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
if err.HasError() {
|
||||
errCh <- E.FailWith("docker connection", err)
|
||||
return
|
||||
}
|
||||
errCh <- err
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
if err.HasError() {
|
||||
errCh <- E.Failure("connecting to docker")
|
||||
return
|
||||
}
|
||||
defer cl.Close()
|
||||
|
||||
cEventCh, cErrCh := cl.Events(ctx, dwOptions)
|
||||
cEventCh, cErrCh := w.client.Events(ctx, options)
|
||||
started <- struct{}{}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if err := <-cErrCh; err != nil {
|
||||
errCh <- E.From(err)
|
||||
if err := E.From(ctx.Err()); err != nil && err.IsNot(context.Canceled) {
|
||||
errCh <- err
|
||||
}
|
||||
return
|
||||
case msg := <-cEventCh:
|
||||
var Action Action
|
||||
switch msg.Action {
|
||||
case events.ActionStart:
|
||||
Action = ActionCreated
|
||||
case events.ActionDie:
|
||||
Action = ActionStopped
|
||||
default: // NOTE: should not happen
|
||||
Action = ActionModified
|
||||
action, ok := events.DockerEventMap[msg.Action]
|
||||
if !ok {
|
||||
w.Debugf("ignored unknown docker event: %s for container %s", msg.Action, msg.Actor.Attributes["name"])
|
||||
continue
|
||||
}
|
||||
eventCh <- Event{
|
||||
Type: EventTypeDocker,
|
||||
event := Event{
|
||||
Type: events.EventTypeDocker,
|
||||
ActorID: msg.Actor.ID,
|
||||
ActorAttributes: msg.Actor.Attributes, // labels
|
||||
ActorName: msg.Actor.Attributes["name"],
|
||||
Action: Action,
|
||||
Action: action,
|
||||
}
|
||||
eventCh <- event
|
||||
case err := <-cErrCh:
|
||||
if err == nil {
|
||||
continue
|
||||
@@ -81,7 +110,7 @@ func (w *DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan E.Nest
|
||||
default:
|
||||
if D.IsErrConnectionFailed(err) {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
cEventCh, cErrCh = cl.Events(ctx, dwOptions)
|
||||
cEventCh, cErrCh = w.client.Events(ctx, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,8 +121,9 @@ func (w *DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan E.Nest
|
||||
return eventCh, errCh
|
||||
}
|
||||
|
||||
var dwOptions = events.ListOptions{Filters: filters.NewArgs(
|
||||
filters.Arg("type", string(events.ContainerEventType)),
|
||||
filters.Arg("event", string(events.ActionStart)),
|
||||
filters.Arg("event", string(events.ActionDie)), // 'stop' already triggering 'die'
|
||||
var optionsWatchAll = DockerListOptions{Filters: NewDockerFilter(
|
||||
DockerFilterContainer,
|
||||
DockerFilterStart,
|
||||
DockerFilterStop,
|
||||
DockerFilterDie,
|
||||
)}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package event
|
||||
|
||||
import "fmt"
|
||||
|
||||
type (
|
||||
Event struct {
|
||||
Type EventType
|
||||
ActorName string
|
||||
ActorID string
|
||||
ActorAttributes map[string]string
|
||||
Action Action
|
||||
}
|
||||
Action string
|
||||
EventType string
|
||||
)
|
||||
|
||||
const (
|
||||
ActionModified Action = "modified"
|
||||
ActionCreated Action = "created"
|
||||
ActionStarted Action = "started"
|
||||
ActionDeleted Action = "deleted"
|
||||
ActionStopped Action = "stopped"
|
||||
|
||||
EventTypeDocker EventType = "docker"
|
||||
EventTypeFile EventType = "file"
|
||||
)
|
||||
|
||||
func (e Event) String() string {
|
||||
return fmt.Sprintf("%s %s", e.ActorName, e.Action)
|
||||
}
|
||||
|
||||
func (a Action) IsDelete() bool {
|
||||
return a == ActionDeleted
|
||||
}
|
||||
49
src/watcher/events/events.go
Normal file
49
src/watcher/events/events.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
dockerEvents "github.com/docker/docker/api/types/events"
|
||||
)
|
||||
|
||||
type (
|
||||
Event struct {
|
||||
Type EventType
|
||||
ActorName string
|
||||
ActorID string
|
||||
ActorAttributes map[string]string
|
||||
Action Action
|
||||
}
|
||||
Action string
|
||||
EventType string
|
||||
)
|
||||
|
||||
const (
|
||||
ActionFileModified Action = "modified"
|
||||
ActionFileCreated Action = "created"
|
||||
ActionFileDeleted Action = "deleted"
|
||||
|
||||
ActionDockerStartUnpause Action = "start"
|
||||
ActionDockerStopPause Action = "stop"
|
||||
|
||||
EventTypeDocker EventType = "docker"
|
||||
EventTypeFile EventType = "file"
|
||||
)
|
||||
|
||||
var DockerEventMap = map[dockerEvents.Action]Action{
|
||||
dockerEvents.ActionCreate: ActionDockerStartUnpause,
|
||||
dockerEvents.ActionStart: ActionDockerStartUnpause,
|
||||
dockerEvents.ActionPause: ActionDockerStartUnpause,
|
||||
dockerEvents.ActionDie: ActionDockerStopPause,
|
||||
dockerEvents.ActionStop: ActionDockerStopPause,
|
||||
dockerEvents.ActionUnPause: ActionDockerStopPause,
|
||||
dockerEvents.ActionKill: ActionDockerStopPause,
|
||||
}
|
||||
|
||||
func (e Event) String() string {
|
||||
return fmt.Sprintf("%s %s", e.ActorName, e.Action)
|
||||
}
|
||||
|
||||
func (a Action) IsDelete() bool {
|
||||
return a == ActionFileDeleted
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/yusing/go-proxy/common"
|
||||
E "github.com/yusing/go-proxy/error"
|
||||
. "github.com/yusing/go-proxy/watcher/event"
|
||||
)
|
||||
|
||||
type fileWatcher struct {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/sirupsen/logrus"
|
||||
E "github.com/yusing/go-proxy/error"
|
||||
. "github.com/yusing/go-proxy/watcher/event"
|
||||
"github.com/yusing/go-proxy/watcher/events"
|
||||
)
|
||||
|
||||
type fileWatcherHelper struct {
|
||||
@@ -81,30 +81,30 @@ func (h *fileWatcherHelper) start() {
|
||||
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-h.w.Events:
|
||||
case fsEvent, ok := <-h.w.Events:
|
||||
if !ok {
|
||||
// closed manually?
|
||||
fsLogger.Error("channel closed")
|
||||
return
|
||||
}
|
||||
// retrieve the watcher
|
||||
w, ok := h.m[path.Base(event.Name)]
|
||||
w, ok := h.m[path.Base(fsEvent.Name)]
|
||||
if !ok {
|
||||
// watcher for this file does not exist
|
||||
continue
|
||||
}
|
||||
|
||||
msg := Event{
|
||||
Type: EventTypeFile,
|
||||
Type: events.EventTypeFile,
|
||||
ActorName: w.filename,
|
||||
}
|
||||
switch {
|
||||
case event.Has(fsnotify.Create):
|
||||
msg.Action = ActionCreated
|
||||
case event.Has(fsnotify.Write):
|
||||
msg.Action = ActionModified
|
||||
case event.Has(fsnotify.Remove), event.Has(fsnotify.Rename):
|
||||
msg.Action = ActionDeleted
|
||||
case fsEvent.Has(fsnotify.Create):
|
||||
msg.Action = events.ActionFileCreated
|
||||
case fsEvent.Has(fsnotify.Write):
|
||||
msg.Action = events.ActionFileModified
|
||||
case fsEvent.Has(fsnotify.Remove), fsEvent.Has(fsnotify.Rename):
|
||||
msg.Action = events.ActionFileDeleted
|
||||
default: // ignore other events
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@ import (
|
||||
"context"
|
||||
|
||||
E "github.com/yusing/go-proxy/error"
|
||||
. "github.com/yusing/go-proxy/watcher/event"
|
||||
"github.com/yusing/go-proxy/watcher/events"
|
||||
)
|
||||
|
||||
type Event = events.Event
|
||||
|
||||
type Watcher interface {
|
||||
Events(ctx context.Context) (<-chan Event, <-chan E.NestedError)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user