// TODO: move protocol to a separate package package client import ( "git.netflux.io/rob/octoplex/internal/domain" "git.netflux.io/rob/octoplex/internal/event" "google.golang.org/protobuf/types/known/timestamppb" pb "git.netflux.io/rob/octoplex/internal/generated/grpc" ) // EventToProto converts an event to a protobuf message. func EventToProto(ev event.Event) *pb.Event { switch evt := ev.(type) { case event.AppStateChangedEvent: return buildAppStateChangeEvent(evt) case event.DestinationAddedEvent: return buildDestinationAddedEvent(evt) case event.AddDestinationFailedEvent: return buildAddDestinationFailedEvent(evt) case event.DestinationStreamExitedEvent: return buildDestinationStreamExitedEvent(evt) case event.StartDestinationFailedEvent: return buildStartDestinationFailedEvent(evt) case event.DestinationRemovedEvent: return buildDestinationRemovedEvent(evt) case event.RemoveDestinationFailedEvent: return buildRemoveDestinationFailedEvent(evt) case event.FatalErrorOccurredEvent: return buildFatalErrorOccurredEvent(evt) case event.OtherInstanceDetectedEvent: return buildOtherInstanceDetectedEvent(evt) case event.MediaServerStartedEvent: return buildMediaServerStartedEvent(evt) default: panic("unknown event type") } } // CommandToProto converts a command to a protobuf message. func CommandToProto(command event.Command) *pb.Command { switch evt := command.(type) { case event.CommandAddDestination: return buildAddDestinationCommand(evt) case event.CommandRemoveDestination: return buildRemoveDestinationCommand(evt) case event.CommandStartDestination: return buildStartDestinationCommand(evt) case event.CommandStopDestination: return buildStopDestinationCommand(evt) case event.CommandCloseOtherInstance: return buildCloseOtherInstanceCommand(evt) case event.CommandQuit: return buildQuitCommand(evt) default: panic("unknown command type") } } func buildAppStateChangeEvent(evt event.AppStateChangedEvent) *pb.Event { return &pb.Event{ EventType: &pb.Event_AppStateChanged{ AppStateChanged: &pb.AppStateChangedEvent{ AppState: &pb.AppState{ Source: &pb.Source{ Container: containerToProto(evt.State.Source.Container), Live: evt.State.Source.Live, LiveChangedAt: timestamppb.New(evt.State.Source.LiveChangedAt), Tracks: evt.State.Source.Tracks, ExitReason: evt.State.Source.ExitReason, }, Destinations: destinationsToProto(evt.State.Destinations), BuildInfo: &pb.BuildInfo{ GoVersion: evt.State.BuildInfo.GoVersion, Version: evt.State.BuildInfo.Version, Commit: evt.State.BuildInfo.Commit, Date: evt.State.BuildInfo.Date, }, }, }, }, } } func buildDestinationAddedEvent(evt event.DestinationAddedEvent) *pb.Event { return &pb.Event{ EventType: &pb.Event_DestinationAdded{ DestinationAdded: &pb.DestinationAddedEvent{Url: evt.URL}, }, } } func buildAddDestinationFailedEvent(evt event.AddDestinationFailedEvent) *pb.Event { return &pb.Event{ EventType: &pb.Event_AddDestinationFailed{ AddDestinationFailed: &pb.AddDestinationFailedEvent{Url: evt.URL, Error: evt.Err.Error()}, }, } } func buildDestinationStreamExitedEvent(evt event.DestinationStreamExitedEvent) *pb.Event { return &pb.Event{ EventType: &pb.Event_DestinationStreamExited{ DestinationStreamExited: &pb.DestinationStreamExitedEvent{Name: evt.Name, Error: evt.Err.Error()}, }, } } func buildStartDestinationFailedEvent(evt event.StartDestinationFailedEvent) *pb.Event { return &pb.Event{ EventType: &pb.Event_StartDestinationFailed{ StartDestinationFailed: &pb.StartDestinationFailedEvent{Url: evt.URL, Message: evt.Message}, }, } } func buildDestinationRemovedEvent(evt event.DestinationRemovedEvent) *pb.Event { return &pb.Event{ EventType: &pb.Event_DestinationRemoved{ DestinationRemoved: &pb.DestinationRemovedEvent{Url: evt.URL}, }, } } func buildRemoveDestinationFailedEvent(evt event.RemoveDestinationFailedEvent) *pb.Event { return &pb.Event{ EventType: &pb.Event_RemoveDestinationFailed{ RemoveDestinationFailed: &pb.RemoveDestinationFailedEvent{Url: evt.URL, Error: evt.Err.Error()}, }, } } func buildFatalErrorOccurredEvent(evt event.FatalErrorOccurredEvent) *pb.Event { return &pb.Event{ EventType: &pb.Event_FatalError{ FatalError: &pb.FatalErrorEvent{Message: evt.Message}, }, } } func buildOtherInstanceDetectedEvent(_ event.OtherInstanceDetectedEvent) *pb.Event { return &pb.Event{ EventType: &pb.Event_OtherInstanceDetected{ OtherInstanceDetected: &pb.OtherInstanceDetectedEvent{}, }, } } func buildMediaServerStartedEvent(evt event.MediaServerStartedEvent) *pb.Event { return &pb.Event{ EventType: &pb.Event_MediaServerStarted{ MediaServerStarted: &pb.MediaServerStartedEvent{RtmpUrl: evt.RTMPURL, RtmpsUrl: evt.RTMPSURL}, }, } } func containerToProto(c domain.Container) *pb.Container { var errString string if c.Err != nil { errString = c.Err.Error() } var exitCode *int32 if c.ExitCode != nil { code := int32(*c.ExitCode) exitCode = &code } return &pb.Container{ Id: c.ID, Status: c.Status, HealthState: c.HealthState, CpuPercent: c.CPUPercent, MemoryUsageBytes: c.MemoryUsageBytes, RxRate: int32(c.RxRate), TxRate: int32(c.TxRate), RxSince: timestamppb.New(c.RxSince), ImageName: c.ImageName, PullStatus: c.PullStatus, PullProgress: c.PullProgress, PullPercent: int32(c.PullPercent), RestartCount: int32(c.RestartCount), ExitCode: exitCode, Err: errString, } } func destinationsToProto(inDests []domain.Destination) []*pb.Destination { destinations := make([]*pb.Destination, 0, len(inDests)) for _, d := range inDests { destinations = append(destinations, destinationToProto(d)) } return destinations } func destinationToProto(d domain.Destination) *pb.Destination { return &pb.Destination{ Container: containerToProto(d.Container), Status: destinationStatusToProto(d.Status), Name: d.Name, Url: d.URL, } } func destinationStatusToProto(s domain.DestinationStatus) pb.Destination_Status { switch s { case domain.DestinationStatusStarting: return pb.Destination_STATUS_STARTING case domain.DestinationStatusLive: return pb.Destination_STATUS_LIVE default: return pb.Destination_STATUS_OFF_AIR } } func buildAddDestinationCommand(cmd event.CommandAddDestination) *pb.Command { return &pb.Command{CommandType: &pb.Command_AddDestination{AddDestination: &pb.AddDestinationCommand{Url: cmd.URL}}} } func buildRemoveDestinationCommand(cmd event.CommandRemoveDestination) *pb.Command { return &pb.Command{CommandType: &pb.Command_RemoveDestination{RemoveDestination: &pb.RemoveDestinationCommand{Url: cmd.URL}}} } func buildStartDestinationCommand(cmd event.CommandStartDestination) *pb.Command { return &pb.Command{CommandType: &pb.Command_StartDestination{StartDestination: &pb.StartDestinationCommand{Url: cmd.URL}}} } func buildStopDestinationCommand(cmd event.CommandStopDestination) *pb.Command { return &pb.Command{CommandType: &pb.Command_StopDestination{StopDestination: &pb.StopDestinationCommand{Url: cmd.URL}}} } func buildCloseOtherInstanceCommand(event.CommandCloseOtherInstance) *pb.Command { return &pb.Command{CommandType: &pb.Command_CloseOtherInstances{CloseOtherInstances: &pb.CloseOtherInstancesCommand{}}} } func buildQuitCommand(event.CommandQuit) *pb.Command { return &pb.Command{CommandType: &pb.Command_Quit{Quit: &pb.QuitCommand{}}} }