Class: Wee::Session

Inherits:
RequestHandler show all
Defined in:
lib/wee/session.rb,
lib/wee/continuation/session.rb

Direct Known Subclasses

OgSession, PagelessSession

Instance Attribute Summary collapse

Attributes inherited from RequestHandler

#application, #expire_after, #id, #max_lifetime, #max_requests

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from RequestHandler

#alive?, #statistics, #teminate

Constructor Details

#initialize(&block) ⇒ Session

Returns a new instance of Session.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/wee/session.rb', line 13

def initialize(&block)
  Thread.current[:wee_session] = self

  @idgen = Wee::SimpleIdGenerator.new

  # to serialize the requests we need a mutex
  @mutex = Mutex.new    

  block.call(self)

  raise ArgumentError, "No root component specified" if @root_component.nil?
  raise ArgumentError, "No page_store specified" if @page_store.nil?
  
  @initial_snapshot = snapshot()

  super()
ensure
  Thread.current[:wee_session] = nil
end

Instance Attribute Details

#page_storeObject

Returns the value of attribute page_store.



5
6
7
# File 'lib/wee/session.rb', line 5

def page_store
  @page_store
end

#propertiesObject

                                                                        • -

:section: Properties

                                                                        • -



161
162
163
# File 'lib/wee/session.rb', line 161

def properties
  @properties
end

#root_componentObject

Returns the value of attribute root_component.



5
6
7
# File 'lib/wee/session.rb', line 5

def root_component
  @root_component
end

Class Method Details

.currentObject



7
8
9
10
11
# File 'lib/wee/session.rb', line 7

def self.current
  sess = Thread.current[:wee_session]
  raise "not in session" if sess.nil?
  return sess
end

Instance Method Details

#awakeObject

Is called before process_request is invoked Can be used to setup e.g. a database connection.



66
67
# File 'lib/wee/session.rb', line 66

def awake
end

#create_page(snapshot) ⇒ Object



59
60
61
62
# File 'lib/wee/session.rb', line 59

def create_page(snapshot)
  idgen = Wee::SimpleIdGenerator.new
  page = Wee::Page.new(snapshot, Wee::CallbackRegistry.new(idgen))
end

#current_callbacksObject



153
154
155
# File 'lib/wee/session.rb', line 153

def current_callbacks
  @page.callbacks
end

#current_contextObject



149
150
151
# File 'lib/wee/session.rb', line 149

def current_context
  @context
end

#get_property(prop, klass) ⇒ Object

Returns an “owned” property for the given klass.



165
166
167
168
169
170
171
# File 'lib/wee/session.rb', line 165

def get_property(prop, klass)
  if @properties
    @properties.fetch(klass, {})[prop]
  else
    nil
  end
end

#handle_request(context) ⇒ Object

called by application to send the session a request



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/wee/session.rb', line 40

def handle_request(context)
  @mutex.synchronize do
    begin
      Thread.current[:wee_session] = self
      @context = context
      super
      awake
      process_request
      sleep
    rescue Exception => exn
      set_response(context, Wee::ErrorResponse.new(exn))
    ensure
      Thread.current[:wee_session] = nil
      @context = nil
      @page = nil
    end
  end
end

#process_requestObject



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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
# File 'lib/wee/session.rb', line 74

def process_request
  if @context.request.page_id.nil?

    # No page_id was specified in the URL. This means that we start with a
    # fresh component and a fresh page_id, then redirect to render itself.

    handle_new_page_view(@context, @initial_snapshot)

  elsif @page = @page_store.fetch(@context.request.page_id, false)

    # A valid page_id was specified and the corresponding page exists.

    @page.snapshot.restore if @context.request.page_id != @snapshot_page_id 

    p @context.request.fields if $DEBUG

    if @context.request.fields.empty?

      # No action/inputs were specified -> render page
      #
      # 1. Reset the action/input fields (as they are regenerated in the
      #    rendering process).
      # 2. Render the page (respond).
      # 3. Store the page back into the store

      @page = create_page(@page.snapshot)  # remove all action/input handlers
      respond(@context, @page.callbacks)                    # render
      @page_store[@context.request.page_id] = @page         # store

    else

      # Actions/inputs were specified.
      #
      # We process the request and invoke actions/inputs. Then we generate a
      # new page view. 

      callback_stream = Wee::CallbackStream.new(@page.callbacks, @context.request.fields) 

      if callback_stream.all_of_type(:action).size > 1 
        raise "Not allowed to specify more than one action callback"
      end

      live_update_response = catch(:wee_live_update) {
        catch(:wee_back_to_session) {
          @root_component.process_callbacks_chain(callback_stream)
        }
        nil
      }

      if live_update_response
        # replace existing page with new snapshot
        @page.snapshot = self.snapshot
        @page_store[@context.request.page_id] = @page
        @snapshot_page_id = @context.request.page_id  
        set_response(@context, live_update_response) 
      else
        handle_new_page_view(@context)
      end

    end

  else

    # A page_id was specified in the URL, but there's no page for it in the
    # page store.  Either the page has timed out, or an invalid page_id was
    # specified. 
    #
    # TODO:: Display an "invalid page or page timed out" message, which
    # forwards to /app/session-id

    raise "Not yet implemented"

  end
end

#sleepObject

Is called after process_request is run Can be used to release e.g. a database connection.



71
72
# File 'lib/wee/session.rb', line 71

def sleep
end

#snapshotObject



33
34
35
36
# File 'lib/wee/session.rb', line 33

def snapshot
  @root_component.backtrack_state_chain(snap = Wee::Snapshot.new)
  return snap.freeze
end

#start_request_response_loopObject



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/wee/continuation/session.rb', line 35

def start_request_response_loop
  Thread.abort_on_exception = true
  Thread.new {
    Thread.current[:wee_session] = self
    loop {
      @context = nil

      # get a request, check whether this session is alive after every 5
      # seconds.
      while @context.nil?
        begin
          Timeout.timeout(5) {
            @context = @in_queue.pop
          }
        rescue Timeout::Error
          break unless alive?
        end
      end

      # abort thread if no longer alive
      break if not alive?

      raise "invalid request" if @context.nil?

      begin
        awake
        process_request
        sleep
      rescue Exception => exn
        @context.response = Wee::ErrorResponse.new(exn) 
      end
      @out_queue.push(@context)
    }
    p "session loop terminated" if $DEBUG
  }
end