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

Inherits:
Object
  • Object
show all
Extended by:
Logger::Hierarchy
Includes:
Hooks::InstanceHooks, Hooks
Defined in:
lib/roby/interface/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.



88
89
90
91
92
93
94
95
96
97
98
# File 'lib/roby/interface/async/log.rb', line 88

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:



73
74
75
# File 'lib/roby/interface/async/log.rb', line 73

def client
  @client
end

#connection_futureObject (readonly)

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



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

def connection_future
  @connection_future
end

#hostObject (readonly)

Returns the value of attribute host.



69
70
71
# File 'lib/roby/interface/async/log.rb', line 69

def host
  @host
end

#plan_rebuilderRoby::DRoby::PlanRebuilder (readonly)

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



28
29
30
# File 'lib/roby/interface/async/log.rb', line 28

def plan_rebuilder
  @plan_rebuilder
end

#portObject (readonly)

Returns the value of attribute port.



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

def port
  @port
end

Instance Method Details

#attempt_connectionObject

Start a connection attempt



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

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

#clear_integratedObject



231
232
233
# File 'lib/roby/interface/async/log.rb', line 231

def clear_integrated
    plan_rebuilder.clear_integrated
end

#closeObject



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

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

#closed?Boolean

Returns:

  • (Boolean)


160
161
162
# File 'lib/roby/interface/async/log.rb', line 160

def closed?
    !!@closed
end

#connected?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/roby/interface/async/log.rb', line 100

def connected?
    !!client
end

#cycle_indexObject



175
176
177
# File 'lib/roby/interface/async/log.rb', line 175

def cycle_index
    plan_rebuilder && plan_rebuilder.cycle_index
end

#cycle_start_timeObject



179
180
181
# File 'lib/roby/interface/async/log.rb', line 179

def cycle_start_time
    plan_rebuilder && 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



84
85
86
# File 'lib/roby/interface/async/log.rb', line 84

def default_plan_rebuilder
    DRoby::PlanRebuilder.new
end

#init_done?Boolean

Returns:

  • (Boolean)


183
184
185
# File 'lib/roby/interface/async/log.rb', line 183

def init_done?
    client && client.init_done?
end

#on_init_donevoid

This method returns an undefined value.

Hooks called when we finished processing the initial set of data



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

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



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

define_hooks :on_init_progress

#on_reachablevoid

This method returns an undefined value.

Hooks called when we successfully connected



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

define_hooks :on_reachable

#on_unreachablevoid

This method returns an undefined value.

Hooks called when we got disconnected



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

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)


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

define_hooks :on_update

#planRoby::Plan

The plan self is working on

Returns:



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

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



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/roby/interface/async/log.rb', line 121

def poll(max: 0.1)
    if connected?
        if client.read_and_process_pending(max: max)
            return STATE_PENDING_DATA
        else return STATE_CONNECTED
        end
    elsif !closed?
        poll_connection_attempt
        return STATE_DISCONNECTED
    end
rescue Interrupt
    close
    raise

rescue ComError
    Log.info "link closed, trying to reconnect"
    unreachable!
    if !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!
    if !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



192
193
194
195
196
197
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
# File 'lib/roby/interface/async/log.rb', line 192

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)


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

def reachable?
    !!client
end

#scheduler_stateSchedulers::State

Information about the scheduler state

Returns:



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

def scheduler_state; plan.consolidated_scheduler_state end

#unreachable!Object



152
153
154
155
156
157
158
# File 'lib/roby/interface/async/log.rb', line 152

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