Class: Roby::Interface::V1::Async::Log

Inherits:
Object
  • Object
show all
Extended by:
Logger::Hierarchy
Includes:
Hooks, Hooks::InstanceHooks
Defined in:
lib/roby/interface/v1/async/log.rb

Overview

Asynchronous access to the log stream

Roby logs are purely incremental information, which means that on connection one must process the whole existing log before being able to provide the current state. From a user perspective, this init phase is really overhead, so it’s better to avoid updating the UI while the data is being processed. For this reason, the class provides #on_init_progress and #on_init_done to provide progress information to the user, and start normal processing when init is finished.

It must be integrated into your application’s event loop by calling #poll.

Constant Summary collapse

DEFAULT_HOST =
"localhost"
DEFAULT_PORT =
Roby::DRoby::Logfile::Server::DEFAULT_PORT
STATE_DISCONNECTED =
:disconnected
STATE_CONNECTED =
:connected
STATE_PENDING_DATA =
:pending_data

Instance Attribute Summary collapse

Hooks collapse

Instance Method Summary collapse

Methods included from Hooks

included

Constructor Details

#initialize(host = DEFAULT_REMOTE_NAME, port: DEFAULT_PORT, connect: true, plan_rebuilder: default_plan_rebuilder) ⇒ Log

Returns a new instance of Log.



94
95
96
97
98
99
100
101
102
103
104
# File 'lib/roby/interface/v1/async/log.rb', line 94

def initialize(host = DEFAULT_REMOTE_NAME, port: DEFAULT_PORT, connect: true,
               plan_rebuilder: default_plan_rebuilder)
    @host = host
    @port = port
    @plan_rebuilder = plan_rebuilder
    @first_connection_attempt = true
    @closed = false
    if connect
        attempt_connection
    end
end

Instance Attribute Details

#clientRoby::DRoby::Logfile::Client? (readonly)

Returns the object used to communicate to the server, or nil if we have not managed to connect yet.

Returns:



79
80
81
# File 'lib/roby/interface/v1/async/log.rb', line 79

def client
  @client
end

#connection_futureObject (readonly)

The future used to connect to the remote process without blocking the main event loop



82
83
84
# File 'lib/roby/interface/v1/async/log.rb', line 82

def connection_future
  @connection_future
end

#hostObject (readonly)

Returns the value of attribute host.



76
77
78
# File 'lib/roby/interface/v1/async/log.rb', line 76

def host
  @host
end

#plan_rebuilderRoby::DRoby::PlanRebuilder (readonly)

The plan rebuilder object, which processes the log stream to rebuild #plan



31
32
33
# File 'lib/roby/interface/v1/async/log.rb', line 31

def plan_rebuilder
  @plan_rebuilder
end

#portObject (readonly)

Returns the value of attribute port.



76
77
78
# File 'lib/roby/interface/v1/async/log.rb', line 76

def port
  @port
end

Instance Method Details

#attempt_connectionObject

Start a connection attempt



111
112
113
114
115
116
# File 'lib/roby/interface/v1/async/log.rb', line 111

def attempt_connection
    @connection_future = Concurrent::Future.new do
        Roby::DRoby::Logfile::Client.new(host, port)
    end
    connection_future.execute
end

#clear_integratedObject



237
238
239
# File 'lib/roby/interface/v1/async/log.rb', line 237

def clear_integrated
    plan_rebuilder.clear_integrated
end

#closeObject



170
171
172
173
174
# File 'lib/roby/interface/v1/async/log.rb', line 170

def close
    @closed = true
    unreachable!
    plan_rebuilder.clear
end

#closed?Boolean

Returns:

  • (Boolean)


166
167
168
# File 'lib/roby/interface/v1/async/log.rb', line 166

def closed?
    !!@closed
end

#connected?Boolean

Returns:

  • (Boolean)


106
107
108
# File 'lib/roby/interface/v1/async/log.rb', line 106

def connected?
    !!client
end

#cycle_indexObject



181
182
183
# File 'lib/roby/interface/v1/async/log.rb', line 181

def cycle_index
    plan_rebuilder&.cycle_index
end

#cycle_start_timeObject



185
186
187
# File 'lib/roby/interface/v1/async/log.rb', line 185

def cycle_start_time
    plan_rebuilder&.cycle_start_time
end

#default_plan_rebuilderObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Create a plan rebuilder for use in the async object



90
91
92
# File 'lib/roby/interface/v1/async/log.rb', line 90

def default_plan_rebuilder
    DRoby::PlanRebuilder.new
end

#init_done?Boolean

Returns:

  • (Boolean)


189
190
191
# File 'lib/roby/interface/v1/async/log.rb', line 189

def init_done?
    client&.init_done?
end

#on_init_donevoid

This method returns an undefined value.

Hooks called when we finished processing the initial set of data



65
# File 'lib/roby/interface/v1/async/log.rb', line 65

define_hooks :on_init_done

#on_init_progress {|rx, init_size| ... } ⇒ void

This method returns an undefined value.

Yield Parameters:

  • rx (Integer)

    the amount of bytes processed so far

  • init_size (Integer)

    the amount of bytes expected to be received for the init phase



62
# File 'lib/roby/interface/v1/async/log.rb', line 62

define_hooks :on_init_progress

#on_reachablevoid

This method returns an undefined value.

Hooks called when we successfully connected



55
# File 'lib/roby/interface/v1/async/log.rb', line 55

define_hooks :on_reachable

#on_unreachablevoid

This method returns an undefined value.

Hooks called when we got disconnected



59
# File 'lib/roby/interface/v1/async/log.rb', line 59

define_hooks :on_unreachable

#on_update {|cycle_index, cycle_time| ... } ⇒ void

This method returns an undefined value.

Hooks called when the plan rebuilder processed an update

Yield Parameters:

  • cycle_index (Integer)
  • cycle_time (Time)


72
# File 'lib/roby/interface/v1/async/log.rb', line 72

define_hooks :on_update

#planRoby::Plan

The plan self is working on

Returns:



36
37
38
# File 'lib/roby/interface/v1/async/log.rb', line 36

def plan
    plan_rebuilder.plan
end

#poll(max: 0.1) ⇒ (Boolean,Boolean)

Active part of the async. This has to be called regularly within the system’s main event loop (e.g. Roby’s, Vizkit’s or Qt’s)

Returns:

  • ((Boolean,Boolean))

    true if we are connected to the remote server and false otherwise



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/roby/interface/v1/async/log.rb', line 127

def poll(max: 0.1)
    if connected?
        if client.read_and_process_pending(max: max)
            STATE_PENDING_DATA
        else
            STATE_CONNECTED
        end
    elsif !closed?
        poll_connection_attempt
        STATE_DISCONNECTED
    end
rescue Interrupt
    close
    raise
rescue ComError
    Log.info "link closed, trying to reconnect"
    unreachable!
    unless closed?
        attempt_connection
    end
    false
rescue Exception => e
    Log.warn "error while polling connection, trying to reconnect"
    Roby.log_exception_with_backtrace(e, Log, :warn)
    unreachable!
    unless closed?
        attempt_connection
    end
    false
end

#poll_connection_attemptObject

Verify the state of the last connection attempt

It checks on the last connection attempt, and sets #client if it was successful, as well as call the callbacks registered with #on_reachable



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/roby/interface/v1/async/log.rb', line 198

def poll_connection_attempt
    return if client
    return if closed?

    if connection_future.complete?
        case e = connection_future.reason
        when ConnectionError, ComError
            Interface.info "Async::Log failed connection attempt: #{e}"
            attempt_connection
            if @first_connection_attempt
                @first_connection_attempt = false
                run_hook :on_unreachable
            end
            nil
        when NilClass
            Interface.info "successfully connected"
            @client = connection_future.value
            plan_rebuilder.clear
            run_hook :on_reachable

            client.on_init_progress do |received, expected|
                run_hook :on_init_progress, received, expected
            end
            client.on_init_done do
                run_hook :on_init_done
            end
            client.on_data do |data|
                plan_rebuilder.process_one_cycle(data)
                cycle = plan_rebuilder.cycle_index
                time  = plan_rebuilder.cycle_start_time
                Interface.debug "Async update(#{cycle}, #{time})"
                run_hook :on_update, cycle, time
            end
        else
            raise connection_future.reason
        end
    end
end

#reachable?Boolean

True if we are connected to a client

Returns:

  • (Boolean)


177
178
179
# File 'lib/roby/interface/v1/async/log.rb', line 177

def reachable?
    !!client
end

#scheduler_stateSchedulers::State

Information about the scheduler state

Returns:



43
44
45
# File 'lib/roby/interface/v1/async/log.rb', line 43

def scheduler_state
    plan.consolidated_scheduler_state
end

#unreachable!Object



158
159
160
161
162
163
164
# File 'lib/roby/interface/v1/async/log.rb', line 158

def unreachable!
    if client
        client.close unless client.closed?
        @client = nil
        run_hook :on_unreachable
    end
end