itpp-labs / pos-addons

Odoo POS Addons
https://itpp.dev
MIT License
366 stars 582 forks source link

Sync server on Raspberry #644

Open blaggacao opened 6 years ago

blaggacao commented 6 years ago

I open this issue in order to discuss some design choices and in order to prepare the sync server to be baked into a raspberry pi...

CORS in POS BOX

Examples:

  200:     @http.route('/hw_proxy/open_cashbox', type='json', auth='none', cors='*')
  201      def open_cashbox(self):
  202          print 'open_cashbox'
  203  
  204:     @http.route('/hw_proxy/print_receipt', type='json', auth='none', cors='*')
  205      def print_receipt(self, receipt):
  206          print 'print_receipt' + str(receipt)
  207  
  208:     @http.route('/hw_proxy/is_scanner_connected', type='json', auth='none', cors='*')
  209      def is_scanner_connected(self, receipt):
  210          print 'is_scanner_connected?'
  211          return False
  212  
  213:     @http.route('/hw_proxy/scanner', type='json', auth='none', cors='*')
  214      def scanner(self, receipt):
  215          print 'scanner'

CORS in web

The only other module which makes use of cors is web - which happens to be a server wide module!!

Sessionless preflight request & server wide modules

Of course, this is not surprising as preflight requests doe not convey a session, so no db can be inferred. As a result it will be routed through odoo's non db routing table. Only server wide modules are reflected in this table.

Lab Instructions:

Make a patch putting cors='*' on all synch methods (/longpolling/poll through a controller override , /pos_multi_session_sync/update, /pos_longpolling/update). Put a breakpoint here:

# odoo/http.py
            def _dispatch_nodb():
                if request.httprequest.path == '/pos_multi_session_sync/update'
                        import pdb; pdb.set_trace()
                try:
                    func, arguments = self.nodb_routing_map.bind_to_environ(request.httprequest.environ).match()
                except werkzeug.exceptions.HTTPException, e:
                    return request._handle_exception(e)
                request.set_handler(func, arguments, "none")
                result = request.dispatch()
                return result

Please note: In nondb routing, however, cors check is not implemented (-able!) as we cannot know if a given route is available on a given database.

Looking at the code more thouroughly, we could make the pos_longpolling and pos_multi_session_sync and ultimately the bus modules server wide modules on the raspberry so that a route is encountered for the request even without sending a session. Then with allowing for cors="*" we effectively enable that the preflight request will return 200 and we can access the resource even from another origin. Yeah!

The actual request, then will be done with a session, so a full environment should be available (I'll look at the persistence aspects in db of the sync requests in a moment..)

ControllerType gotchas

Interestingly enough, inheriting BusController like here: https://github.com/it-projects-llc/pos-addons/blob/fe1e50ce94efd6412b5444a968589eca35910ac4/pos_longpolling/controllers/pos_longpolling_controller.py#L16 brakes the route detection of server wide modules (who knows why this is in place*): https://github.com/odoo/odoo/blob/fcb48b724152db876f6752560cce5a5d875e8f46/odoo/http.py#L913

so the question is in order for this to work (without patching upstream): Is it really necessary to inherit from BusController?

* EDIT: I think this check is in place to avoide accounting for overridden routes twice (or more times). Contrarily this means you are only supposed to inherit from different than Controller for actually overriding methods...


Conslusion

I think this strategy is what the pos box itself does and is cleaner than putting a nginx in front.

Putting the nginx in front is another infrastructure component and I don't want to be the person to bake that into a raspberry and maintain it afterwards, once deployed... (as a general reluctance, might be quite easy in fact)

--- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/55969617-sync-server-on-raspberry?utm_campaign=plugin&utm_content=tracker%2F2289114&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F2289114&utm_medium=issues&utm_source=github).
blaggacao commented 6 years ago

@KolushovAlexandr Alexander, I have the strong feeling after doing a local setup and walking through this that the if the sync server is another host (only changing port might not be enough), that the call to '/pos_multi_session_sync/update' does not include session cookie. Therfore, there is no environment to do things like: request.env["pos_multi_session_sync.multi_session"]... I'll be investigating

blaggacao commented 6 years ago

I have a damn strong feeling that the current design won't work with a local syncing server due to db/session synchronization and cors issues... I'll try to pull together a (big) refactoring PR in order to implement a satellite bus server and feed back. I think it's easiest to communicate my ideas through code...

However it would be great to be able to have a chat about this maybe on skype?

yelizariev commented 6 years ago

pos_multi_session_sync actually works and has setup instruction . It requires nginx, but I believe it's possible to remove that requirement. Also, the current implementation uses database to store sync data.

So, it works, but it's implemented very naively. I like your idea to don't use nginx. Using non-db environment could be good, but it means that we cannot use orm, which probably means that we need to use different approach (key-value storage?). Ideally, we need to make "Sync Raspberry" read-only (as it's done for POSBOX) to simplify deployment and protect Raspberry from different disk-related problems

blaggacao commented 6 years ago

pos_multi_session_sync actually works and has setup instruction . It requires nginx, but I believe it's possible to remove that requirement.

Are you sure about this? I have a feeling that odoo's same origin check is not very robust, compared for example to pollymer's same origin check. So If you simulate a satellite server by just another port, you might get hit by odoo's week implementation. At least that's a problem I stumbled over by doing all cors stuff to avoide nginx and then using as server 192.168.0.3 while origin was localhost. This lead to that no session is sent in the request which makes it basically a nodb request with all it's implications...

EDIT: I'm working on a refactoring and will come up with a (bigger) PR hopefully soon, which can then be thorn apart in it's different suggestions...

I'm working on making buses in pos_longpolling true bi-directional communication channels with two hardcoded endpoints (/lonpolling/push & /longpolling/send) either towards 'origin' or towards 'satellite' or any other endpoint who might be connected with any POS (a queue connecting to an online order platform? :smile: ).

I haven't reached yet the nondb environment problem.. I was planning to hack something into the pos box with the tools already present, there...