How do I make my image recourses synchronize for clients when they change on the host?

22 Views Asked by At

I am currently working with pyramid and have a png that changes as users interact with the site. I would like it to update on the client when it is modified on the server. As of now you have to refresh the page to see the newest version but I would like this to be automatic. My current project has the relevant code starting with some configuration.

@view_config(route_name='png')
def test_page(request):
    response = FileResponse(
        './home.png',
        request=request,
        content_type='image/png'
        )
    return response

and this in main:

config.add_route('png', '/home.png')
config.scan('__main__')

enabling this in a response to show the image.

var background = new Image();
    background.src = "home.png";
    background.onload = function(){
        ctx.drawImage(background,0,0);   
    }

I'm not exactly sure how I should go about changing this however I have considered just setting an event on a timer to reload and redraw the image but obviously that isn't triggered by the resource change so kind feels wrong, I don't know. And when I tried to set a timer it didn't work.

setInterval(() => {
    var background = new Image();
    background.src = "home.png";
    ctx.drawImage(background,0,0);
    console.log("Check 1,2")
}, 1000*15);
1

There are 1 best solutions below

0
Sergey On

"Normal" web is one-way: the client requests a resource from the server, the server returns a response, done. The server in this model is always passive - there's no way for the server to initiate a connection to the client, it only responds to requests. So, in this model your only option is to periodically poll the server from the client, which, as you said, may not be super-efficient. But, depending on your requirements, it may be an easier and acceptable option.

(One possible optimisation here would be to add a /has_image_changed_since?date=xxx route so the client can quickly check whether it needs to reload the image instead of reloading it every time).

But, of course, depending on how often the image refreshes, how many clients your app has and what is the acceptable latency between the image changing on the server and the change reflected on the client - this approach may not scale well.

To overcome this one-way limitation there's a thing called WebSocket which allows two-way asynchronous communication between the web page and the server - conceptually, once the page is loaded, the JS code on the page establishes a persistent two-way connection to the server and the server is then able to push messages to all connected clients - for example, when a file changes on the filesystem. The clients, upon receiving a message, may do things such as reloading and redrawing an image.

Pyramid, being a "traditional" request/response framework, is not very well suited to this kind of asynchronous programming (or maintaining a large number of open idle connections). For sending asynchronous file change notifications you'd probably need a separate app built using an asynchronous web framework, such as Tornado - it would be a simple separate process which watches for file changes (say, using python-watchdog) and sends a message to the connected clients (say, using tornado-websocket)