I’m digging into Hops lately and so far loving it! But although I read quite a lot about it, I’m still asking myself:
Is it possible to run a ghhops-server instance on one computer and query the available endpoints from another computer in the local network?
@stevebaer could you give me a hint if/how this can be done? Or do I need to deploy a “real” compute server for this?
Yes, but you must allow incoming connections to your computer or wherever the Flask server is running from. This isn’t done in Python or Rhino, but rather in the network preferences of your OS.
If you set the host parameter of your Flask app to 0.0.0.0, the server will be accessible from <your ip>:5000 on any computer on your local network.
That’s already helpful, thanks! Do you know by any chance if that’s also possible without using flask?
I need RhinoCommon functionality so I can’t go the flask route
You can choose to use Rhino.Inside or not use Rhino.Inside with ghhops-server. It depends on if you need the functionality provided by have access to all of RhinoCommon and Grasshopper or if you can get by with the functionality provided by rhino3dm. In either case you can choose to use flask or not use flask. It doesn’t matter.
Hey Steve,
sorry to keep bothering, but from reading the code I can either register rhinoinside as a Middleware when initializing hops OR use flask as a Middleware.
I would actually be very happy if both together were possible, so if that’s the case could you provide an example how to do it?
Yes, I also realize that the comment says it would not be strictly necessary. So it’s definitely not my goal to be some know-it-all, I just want to understand it and see if I can use it for a project with my students. That’s the reason I asked for an example before modifying the code or doing lots of trial and error.
Still would be very grateful for any further tips.
# determine the correct middleware base on the source app being wrapped
# when running standalone with no source apps
if app is None:
hlogger.debug("Using Hops default http server")
params._init_rhino3dm()
return hmw.HopsDefault()
# if wrapping another app
app_type = repr(app)
# if app is Flask
if app_type.startswith("<Flask"):
hlogger.debug("Using Hops Flask middleware")
params._init_rhino3dm()
return hmw.HopsFlask(app, *args, **kwargs)
# if wrapping rhinoinside
# paractically this is not necessary. it is implemented this way
# mostly to provide a level of consistency on how Hops is used
elif app_type.startswith("<module 'rhinoinside'"):
# detemine if running with rhino.inside.cpython
# and init the param module accordingly
if not Hops.is_inside():
raise Exception("rhinoinside is not loaded yet")
hlogger.debug("Using Hops default http server with rhinoinside")
params._init_rhinoinside()
return hmw.HopsDefault(*args, **kwargs)
raise Exception("Unsupported app")
I just tried it out by changing the code to use flask as well as rhinoinside, works out of the box.
I would argue that hops server should differentiate between server type (Hops HTTP or Flask) and app type (rhino3dm or rhinoinside). Throwing these into the same basket (like it is implemented at the moment) does not make sense to me and I would very much appreciate a fix/change to the official code @eirannejad@stevebaer . I’ll gladly contribute a suggestion via pull request but I don’t know if you would even consider, so I’m waiting for a sign
EDIT:
Should anyone encounter the same problem, here is my workaround code that just subclasses the Hops class while introducing a force_rhinoinside option. I’m sure it can be solved more elegantly, but this is a quick WFM solution:
import ghhops_server as hs
class CustomHops(hs.Hops):
"""Custom Hops Middleware allowing Flask app to also run Rhino.Inside"""
def __new__(cls,
app=None,
debug=False,
force_rhinoinside=False,
*args,
**kwargs) -> hs.base.HopsBase:
# set logger level
hs.hlogger.setLevel(hs.logging.DEBUG if debug else hs.logging.INFO)
# determine the correct middleware base on the source app being wrapped
# when running standalone with no source apps
if app is None:
hs.hlogger.debug("Using Hops default http server")
hs.params._init_rhino3dm()
return hs.middlewares.HopsDefault()
# if wrapping another app
app_type = repr(app)
# if app is Flask
if app_type.startswith("<Flask"):
if force_rhinoinside:
hs.hlogger.debug("Using Hops Flask middleware and rhinoinside")
hs.params._init_rhinoinside()
else:
hs.hlogger.debug("Using Hops Flask middleware and rhino3dm")
hs.params._init_rhino3dm()
return hs.middlewares.HopsFlask(app, *args, **kwargs)
# if wrapping rhinoinside
elif app_type.startswith("<module 'rhinoinside'"):
# determine if running with rhino.inside.cpython
# and init the param module accordingly
if not CustomHops.is_inside():
raise Exception("rhinoinside is not loaded yet")
hs.hlogger.debug("Using Hops default http server with rhinoinside")
hs.params._init_rhinoinside()
return hs.middlewares.HopsDefault(*args, **kwargs)
raise Exception("Unsupported app!")