Comments (18)
Hi Davide
Thanks a lot.
from remi.
Hello,
Remi allows to create graphical interfaces for python applications. Such interfaces are accessible from everywhere in your network. I suggest to only expose such applications in private networks or VPN.
Kind Regards.
from remi.
Thanks Davide,
I have some experiace with TKinter for standalone app, but now I need a tool like Remi to convert my codes to network user (in VPN format), so I think Remi can be appropaite for this purpose.
I need just a small script to found out how I can create an shared interface under SAAS form.
Thanks again
from remi.
I would be pleaded to help you, but you should give me more details about the requirements. Remi allows to create ui. SaaS is a sw architecture to make an application running as a service, maybe giving it a REST interface. Here we have two different things.. what you want to do exactly?
from remi.
I would like to create an interface for a code, that a user on our internal network can run it from his pc (remote access, without having access to the code, just by having access to the web interface), then the user can give and change some parameters and may be able to view results (calculation results) and some generated graphes.
from remi.
There are different examples about remi in this folder
https://github.com/rawpython/remi/tree/master/examples
Additionally there is a graphical editor that can help you design your interface.
from remi.
already I tested some of them, but a problem that I have, is how can I run one simple exmple in this series of test codes from another pc.
I can not configure IP adresse inside of code, to have acces from another pc.
So, real issue it s how can I configure acces with IP adresse ou other way to arrive runing graphic interface via remote PC.
Thanks a lot
from remi.
At the end of the script there is the "start" function call, there an ip address is passed as parameter. Set that ip address as 0.0.0.0 and the ui will be reachable from every device in the network
from remi.
I try one example on same wifi connection
I have GUI on my runing PC with this adresse http://127.0.0.1:8081/
but I can not see the same page from another PC.
it is not work for me!!
from remi.
On the other machine you should access a different url. The ip address in the url must be the ipaddress of the machine running the application.
http://correct_ip:8081/
from remi.
@Ali-RAFIEE did you get it working?
from remi.
Thank you very much Davide
That works.
but is it possible to convert the access into a https secure access?
and also how can i get my code to run directly from a remote PC?
Thanks.
from remi.
I'm pleased to help.
Of course it is possible to use https, but you need to create certificates.
You can run your program on every kind of machine, and you can access your interface from everywhere. What you mean for executing the code directly from the remote PC?
from remi.
currently I run my code on my PC and I manage to have the Gui interface on another PC.
but in fact I would like to run the code directly from the remote pc without having to run it first on the PC hosting the code.
from remi.
Do I have to keep the main interface open all the time on the server PC to run a code?
Indeed I want to have the first page which checks the username and password of each user, then if a user wants to do calculations he can perform and at the same time the software home page can accept multiple users simultaneously. Is it possible with Remi? Any simple example?
Thanks a lot
from remi.
You have to run the script on the server. You can open and close the interface when you want, the server will continue to listen for new connections. Of course different users can connect to the interface at the same time and perform login separately
from remi.
And last question:
should I create two separate pages, one for logging (verifying username and password) and another to give access to the user to run the main code?
and how can I manage to get multiple users working simultaneously with the same code but with different inputs and therefore different results to illustrate? should I generate a different port number for each new user?
if there is a simple example it is welcome, starting a new challenge is always a harder part of a project.
Thanks again
from remi.
Hello @Ali-RAFIEE ,
Here is an example for you. It is an advanced example, I'm sure you can simplify it.
import remi.gui as gui
from remi.gui import *
from remi import start, App
import random
import threading
class CookieInterface(gui.Tag, gui.EventSource):
def __init__(self, remi_app_instance, **kwargs):
super(CookieInterface, self).__init__(**kwargs)
gui.EventSource.__init__(self)
self.app_instance = remi_app_instance
self.EVENT_ONCOOKIES = "on_cookies"
self.cookies = {}
def request_cookies(self):
self.app_instance.execute_javascript("""
var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
var result = {};
for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) {
var key = decodeURIComponent(aKeys[nIdx]);
result[key] = decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
}
sendCallbackParam('%s','%s', result);
"""%(self.identifier, self.EVENT_ONCOOKIES))
@gui.decorate_event
def on_cookies(self, **value):
self.cookies = value
return (value,)
def remove_cookie(self, key, path='/', domain=''):
if not key in self.cookies.keys():
return
self.app_instance.execute_javascript( """
var sKey = "%(sKey)s";
var sPath = "%(sPath)s";
var sDomain = "%(sDomain)s";
document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "");
"""%{'sKey': key, 'sPath': path, 'sDomain': domain} )
def set_cookie(self, key, value, expiration='Infinity', path='/', domain='', secure=False):
"""
expiration (int): seconds after with the cookie automatically gets deleted
"""
secure = 'true' if secure else 'false'
self.app_instance.execute_javascript("""
var sKey = "%(sKey)s";
var sValue = "%(sValue)s";
var vEnd = eval("%(vEnd)s");
var sPath = "%(sPath)s";
var sDomain = "%(sDomain)s";
var bSecure = %(bSecure)s;
if( (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) == false ){
var sExpires = "";
if (vEnd) {
switch (vEnd.constructor) {
case Number:
sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
break;
case String:
sExpires = "; expires=" + vEnd;
break;
case Date:
sExpires = "; expires=" + vEnd.toUTCString();
break;
}
}
document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
}
"""%{'sKey': key, 'sValue': value, 'vEnd': expiration, 'sPath': path, 'sDomain': domain, 'bSecure': secure})
class User(object):
USER_LEVEL_NOT_AUTHENTICATED = 0
USER_LEVEL_USER = 1
USER_LEVEL_ADMIN = 2
def __init__(self, username, pwd, user_level=0):
self.username = username
self.pwd = pwd
self.user_level = user_level
class LoginManager(gui.Tag, gui.EventSource):
"""
Login manager class allows to simply manage user access safety by session cookies
It requires a cookieInterface instance to query and set user session id
When the user login to the system you have to call
login_manager.renew_session() #in order to force new session uid setup
The session have to be refreshed each user action (like button click or DB access)
in order to avoid expiration. BUT before renew, check if expired in order to ask user login
if not login_manager.expired:
login_manager.renew_session()
#RENEW OK
else:
#UNABLE TO RENEW
#HAVE TO ASK FOR LOGIN
In order to know session expiration, you should register to on_session_expired event
on_session_expired.do(mylistener.on_user_logout)
When this event happens, ask for user login
"""
def __init__(self, user_dictionary, cookieInterface, session_timeout_seconds = 60, **kwargs):
#user_dictionary is a dictionary (the key is the username,
# the value is a User instance) have to be a list of users, can be loaded or other data sources
super(LoginManager, self).__init__(**kwargs)
gui.EventSource.__init__(self)
self.user_dictionary = user_dictionary
self.user_logged_instance = None
self.session_uid = str(random.randint(1,999999999))
self.cookieInterface = cookieInterface
self.session_timeout_seconds = session_timeout_seconds
self.timer_request_cookies() #starts the cookie refresh
self.timeout_timer = None #checks the internal timeout
def timer_request_cookies(self):
self.cookieInterface.request_cookies()
threading.Timer(self.session_timeout_seconds/10.0, self.timer_request_cookies).start()
@gui.decorate_event
def on_session_expired(self):
self.user_logged_instance = None
return ()
def renew_session(self):
"""Have to be called on user actions to check and renew session
"""
if ((not 'user_uid' in self.cookieInterface.cookies) or self.cookieInterface.cookies['user_uid']!=self.session_uid) and (not (self.user_logged_instance==None)):
self.on_session_expired()
if self.user_logged_instance == None:
self.session_uid = str(random.randint(1,999999999))
self.cookieInterface.set_cookie('user_uid', self.session_uid, str(self.session_timeout_seconds))
#here we renew the internal timeout timer
if self.timeout_timer:
self.timeout_timer.cancel()
self.timeout_timer = threading.Timer(self.session_timeout_seconds, self.on_session_expired)
self.timeout_timer.start()
def login(self, username, pwd):
#returns None if not authenticated or a User instance, with the proper user_level
if username in self.user_dictionary.keys():
if pwd == self.user_dictionary[username].pwd:
print("password ok")
self.user_logged_instance = self.user_dictionary[username]
self.renew_session()
return self.user_dictionary[username] #self.user_logged_instance
return None
def add_user(self, user):
#add a new user that can login, you can save it to a database
self.user_dictionary[user.username] = user
class ContainerProxy():
#given a container, this class allows to append widgets to it, keeping memory about widget user level.
# when user level changes, this class hides or shows children widgets properly
def __init__(self, container):
self.container = container
self.widgets_dictionary = {}
def append(self, user_level, widget, key=None):
key = self.container.append(widget, key)
#here we store for each widget, the minimum user level for which it have to be visible
self.widgets_dictionary[key] = {'widget':widget, 'user_level':user_level}
def set_logged_user_level(self, user_level = User.USER_LEVEL_NOT_AUTHENTICATED):
self.user_level = user_level
for widget_id in self.widgets_dictionary.keys():
if self.widgets_dictionary[widget_id]['user_level'] > self.user_level:
#here we replace the widget to hide in order to mantain a placeholder
self.container.append(gui.Widget(style={'display':'none', 'width':'0px', 'height':'0px'}), widget_id)
else:
#here we put again the widget on the interface, the placeholder gets replaced because the same kay is used to append
self.container.append(self.widgets_dictionary[widget_id]['widget'], widget_id)
class MyApp(App):
def __init__(self, *args, **kwargs):
super(MyApp, self).__init__(*args, static_file_path='./res/')
def idle(self):
#idle function called every update cycle
pass
def main(self):
main_container = Container(margin="0px auto")
self.container_proxy = ContainerProxy(main_container)
main_container.attributes.update({"editor_baseclass":"Container","editor_tag_type":"widget","editor_newclass":"False","editor_constructor":"()","class":"Container","editor_varname":"main_container"})
main_container.style.update({"width":"580.0px","position":"relative","overflow":"auto","height":"500.0px"})
user_area_container = Container()
user_area_container.attributes.update({"editor_baseclass":"Container","editor_tag_type":"widget","editor_newclass":"False","editor_constructor":"()","class":"Container","editor_varname":"user_area_container"})
user_area_container.style.update({"width":"260.0px","border-style":"dotted","border-width":"1px","position":"absolute","top":"40.0px","left":"20.0px","margin":"0px","overflow":"auto","height":"440.0px"})
lbl_user_panel = Label('User panel')
lbl_user_panel.attributes.update({"editor_baseclass":"Label","editor_tag_type":"widget","editor_newclass":"False","editor_constructor":"('User panel')","class":"Label","editor_varname":"lbl_user_panel"})
lbl_user_panel.style.update({"width":"100px","position":"absolute","top":"20.0px","left":"20.0px","margin":"0px","overflow":"auto","height":"30px"})
user_area_container.append(lbl_user_panel,'lbl_user_panel')
#main_container.append(user_area_container,'user_area_container')
self.container_proxy.append(User.USER_LEVEL_USER, user_area_container,'user_area_container')
user_auth_container = HBox()
user_auth_container.attributes.update({"editor_baseclass":"HBox","editor_tag_type":"widget","editor_newclass":"False","editor_constructor":"()","class":"HBox","editor_varname":"user_auth_container"})
user_auth_container.style.update({"right":"1px","align-items":"center","visibility":"visible","height":"35px","overflow":"auto","top":"1px","flex-direction":"row","width":"300px","justify-content":"space-around","position":"absolute","margin":"0px","display":"flex"})
bt_user_login = Button('login')
bt_user_login.attributes.update({"editor_baseclass":"Button","editor_tag_type":"widget","editor_newclass":"False","editor_constructor":"('login')","class":"Button","editor_varname":"bt_user_login"})
bt_user_login.style.update({"width":"100px","position":"static","top":"20px","order":"2","margin":"0px","overflow":"auto","height":"30px"})
bt_user_login.onclick.do(self.on_prompt_login)
self.bt_user_login = bt_user_login
user_auth_container.append(bt_user_login,'bt_user_login')
user_name = Label('not logged in')
user_name.attributes.update({"editor_baseclass":"Label","editor_tag_type":"widget","editor_newclass":"False","editor_constructor":"('not logged in')","class":"Label","editor_varname":"user_name"})
user_name.style.update({"width":"100px","font-weight":"bold","position":"static","top":"20px","order":"1","margin":"0px","overflow":"auto","height":"30px"})
self.user_name = user_name
user_auth_container.append(user_name,'user_name')
bt_user_logout = Button('logout')
bt_user_logout.attributes.update({"editor_baseclass":"Button","editor_tag_type":"widget","editor_newclass":"False","editor_constructor":"('logout')","class":"Button","editor_varname":"bt_user_logout"})
bt_user_logout.style.update({"visibility":"visible","height":"30px","overflow":"auto","top":"20px","order":"3","width":"100px","position":"static","margin":"0px","display":"none","background-color":"#fa3200"})
bt_user_logout.onclick.do(self.on_logout)
self.bt_user_logout = bt_user_logout
user_auth_container.append(bt_user_logout,'bt_user_logout')
main_container.append(user_auth_container,'user_auth_container')
admin_area_container = Container()
admin_area_container.attributes.update({"editor_baseclass":"Container","editor_tag_type":"widget","editor_newclass":"False","editor_constructor":"()","class":"Container","editor_varname":"admin_area_container"})
admin_area_container.style.update({"border-color":"#030303","height":"440.0px","border-style":"dotted","overflow":"auto","top":"40.0px","border-width":"1px","width":"260.0px","position":"absolute","margin":"0px","left":"300.0px"})
lbl_admin_panel = Label('Administration panel')
lbl_admin_panel.attributes.update({"editor_baseclass":"Label","editor_tag_type":"widget","editor_newclass":"False","editor_constructor":"('Administration panel')","class":"Label","editor_varname":"lbl_admin_panel"})
lbl_admin_panel.style.update({"width":"158px","position":"absolute","top":"20.0px","left":"20.0px","margin":"0px","overflow":"auto","height":"27px"})
admin_area_container.append(lbl_admin_panel,'lbl_admin_panel')
#main_container.append(admin_area_container,'admin_area_container')
self.container_proxy.append(User.USER_LEVEL_ADMIN, admin_area_container,'admin_area_container')
example_users = {}
example_users['admin'] = User('admin', 'pwdadmin', User.USER_LEVEL_ADMIN)
example_users['user'] = User('user', 'pwduser', User.USER_LEVEL_USER)
self.login_manager = LoginManager(example_users, CookieInterface(self), 60*60) #autologout 1 hour (60 seconds x 60 minutes)
self.login_manager.on_session_expired.do(self.on_logout)
self.main_container = main_container
self.on_logout(None)
return self.main_container
def on_prompt_login(self, emitter):
self.login_dialog = gui.GenericDialog("Login", "Type here login data", width=300)
username_input = gui.TextInput(width=250)
password_input = gui.TextInput(width=250)
self.login_dialog.add_field_with_label('username', 'Username', username_input)
self.login_dialog.add_field_with_label('password', 'Password', password_input)
self.login_dialog.confirm_dialog.do(self.on_login_confirm)
self.login_dialog.show(self)
def on_login_confirm(self, emitter):
username = self.login_dialog.get_field('username').get_value()
password = self.login_dialog.get_field('password').get_value()
user = self.login_manager.login(username, password)
if user != None:
print("logged in")
self.user_name.set_text("hello " + user.username)
self.bt_user_login.style['display'] = 'none'
self.bt_user_logout.style['display'] = 'inline'
self.container_proxy.set_logged_user_level(user.user_level)
def on_renew(self, emitter):
#THIS METHOD HAVE TO BE CALLED EACH TIME A USER DOES SOMETHING ON THE INTERFACE
# IT IS TO SAY EACH "INTERACTION" to keep the access alive, otherwise the user will be disconnected after a timeout
#if the user is still logged in
if not self.login_manager.user_logged_instance is None:
self.login_manager.renew_session()
else:
self.on_logout(None)
def on_logout(self, emitter):
self.bt_user_login.style['display'] = 'inline'
self.bt_user_logout.style['display'] = 'none'
self.user_name.set_text("not logged in")
self.container_proxy.set_logged_user_level()
if __name__ == "__main__":
# starts the webserver
start(MyApp, address='0.0.0.0', port=0, multiple_instance=False, debug=False)
from remi.
Related Issues (20)
- Label and SpinBox widgets do not align HOT 2
- [Question] How to set a textinput blur when user pressed Esc key HOT 2
- got an unexpected keyword argument 'websocket_port HOT 1
- Blank window on standalone_app.py HOT 2
- Labels do not display the correct number of whitespace HOT 1
- [QUESTION] any example of long-polling implementation in remi? HOT 1
- Get selected text from TextInput HOT 6
- automatic scroll down in text widget (write only) HOT 9
- highlight of table cells in front end. HOT 1
- GenericDialog confirm by Enter key pressing HOT 1
- 2 bugs remain for python 3.10 HOT 1
- How to add a radiobox or radiogroup in remi? HOT 1
- How to insert custom HTML
- Javascript gets unloaded after remi reloads with "handshake complete" HOT 3
- Add a button that opens a link HOT 2
- Feature request: Allow setting button labels on GenericDialog
- Editor: export do not work correctlly HOT 1
- Termux Version?
- Offline Plotly HTML Integration HOT 1
- Editor directory conflicts with other packages
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from remi.