def join_workspace(workspace_url, on_auth=None): global agent msg.debug("workspace url is %s" % workspace_url) try: result = utils.parse_url(workspace_url) except Exception as e: return msg.error(str(e)) G.PROJECT_PATH = os.path.realpath( os.path.join(G.COLAB_DIR, result['owner'], result['workspace'])) utils.mkdir(os.path.dirname(G.PROJECT_PATH)) d = '' # TODO: really bad prompt here prompt = "Give me a directory to sync data to (or just press enter): " if not os.path.isdir(G.PROJECT_PATH): while True: d = vim_input(prompt, d, "dir") if d == '': utils.mkdir(G.PROJECT_PATH) break d = os.path.realpath(os.path.expanduser(d)) if os.path.isfile(d): prompt = '%s is not a directory. Enter an existing path (or press enter): ' % d continue if not os.path.isdir(d): try: utils.mkdir(d) except Exception as e: prompt = "Couldn't make dir: %s because %s " % (d, str(e)) continue try: os.symlink(d, G.PROJECT_PATH) break except Exception as e: return msg.error("Couldn't create symlink from %s to %s: %s" % (d, G.PROJECT_PATH, str(e))) G.PROJECT_PATH = os.path.realpath(G.PROJECT_PATH + os.sep) vim.command('cd %s' % G.PROJECT_PATH) msg.debug("joining workspace %s" % workspace_url) stop_everything() try: start_event_loop() agent = AgentConnection(on_auth=on_auth, Protocol=Protocol, **result) # owner and workspace name are slugfields so this should be safe agent.connect() except Exception as e: msg.error(str(e)) tb = traceback.format_exc() msg.debug(tb) stop_everything()
def join_room(room_url, on_auth=None): global agent msg.debug("room url is %s" % room_url) try: result = utils.parse_url(room_url) except Exception as e: return msg.error(str(e)) G.PROJECT_PATH = os.path.realpath(os.path.join(G.COLAB_DIR, result['owner'], result['room'])) utils.mkdir(os.path.dirname(G.PROJECT_PATH)) d = '' # TODO: really bad prompt here prompt = "Give me a directory to sync data to (or just press enter): " if not os.path.isdir(G.PROJECT_PATH): while True: d = vim_input(prompt, d, "dir") if d == '': utils.mkdir(G.PROJECT_PATH) break d = os.path.realpath(os.path.expanduser(d)) if os.path.isfile(d): prompt = '%s is not a directory. Enter an existing path (or press enter): ' % d continue if not os.path.isdir(d): try: utils.mkdir(d) except Exception as e: prompt = "Couldn't make dir: %s because %s " % (d, str(e)) continue try: os.symlink(d, G.PROJECT_PATH) break except Exception as e: return msg.error("Couldn't create symlink from %s to %s: %s" % (d, G.PROJECT_PATH, str(e))) G.PROJECT_PATH = os.path.realpath(G.PROJECT_PATH + os.sep) vim.command('cd %s' % G.PROJECT_PATH) msg.debug("joining room %s" % room_url) stop_everything() try: start_event_loop() agent = AgentConnection(on_auth=on_auth, Protocol=Protocol, **result) # owner and room name are slugfields so this should be safe agent.connect() except Exception as e: msg.error(str(e)) tb = traceback.format_exc() msg.debug(tb) stop_everything()
def run_agent(owner, workspace, host, port, secure): global on_room_info_waterfall if G.AGENT: msg.debug('Stopping agent.') G.AGENT.stop() G.AGENT = None on_room_info_waterfall.add(update_recent_workspaces, {'url': workspace_url}) try: msg.debug("agent_conn_kwargs: %s" % str(agent_conn_kwargs)) G.AGENT = AgentConnection( owner=owner, workspace=workspace, host=host, port=port, secure=secure, on_room_info=on_room_info_waterfall.call, **agent_conn_kwargs) on_room_info_waterfall = utils.Waterfall() Listener.reset() G.AGENT.connect() except Exception as e: print(e) tb = traceback.format_exc() print(tb)
def run_agent(owner, room, host, port, secure): global agent if agent: agent.stop() agent = None try: agent = AgentConnection(owner, room, host=host, port=port, secure=secure, on_connect=ON_CONNECT) # owner and room name are slugfields so this should be safe Listener.set_agent(agent) agent.connect() except Exception as e: print(e) tb = traceback.format_exc() print(tb) else: joined_room = {'url': room_url} update_recent_rooms(joined_room)
def remote_connect(self, workspace_url, on_auth=None, get_bufs=True): G.PROJECT_PATH = os.path.realpath(G.PROJECT_PATH) G.PROJECT_PATH += os.sep self.agent = AgentConnection(Protocol=Protocol, workspace_url=workspace_url, on_auth=on_auth, get_bufs=get_bufs, conn=self) self.agent.connect()
def run_agent(owner, room, host, port, secure): global agent if agent: msg.debug('Stopping agent.') agent.stop() agent = None try: agent = AgentConnection(owner, room, host=host, port=port, secure=secure, on_connect=ON_CONNECT) # owner and room name are slugfields so this should be safe Listener.set_agent(agent) agent.connect() except Exception as e: print(e) tb = traceback.format_exc() print(tb) else: joined_room = {'url': room_url} update_recent_rooms(joined_room)
class EmacsConnection(object): def __init__(self): self.to_emacs_q = [] self.net_buf = '' self.agent = None self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.bind(('localhost', 4567)) self.sock.listen(1) self.user_inputs = {} self.user_input_count = 0 def get_input(self, prompt, initial, cb, *args, **kwargs): event = { 'id': self.user_input_count, 'prompt': prompt, 'initial': initial, } if 'choices' in kwargs: event['choices'] = kwargs['choices'] elif 'y_or_n' in kwargs: event['y_or_n'] = True del kwargs['y_or_n'] self.put('user_input', event) self.user_inputs[self.user_input_count] = lambda x: cb(x, *args, **kwargs) self.user_input_count += 1 def start(self): print('started') self.conn, addr = self.sock.accept() self.conn.setblocking(0) self.select() def remote_connect(self, workspace_url, on_auth=None): G.PROJECT_PATH = os.path.realpath(G.PROJECT_PATH) G.PROJECT_PATH += os.sep self.agent = AgentConnection(Protocol=Protocol, workspace_url=workspace_url, on_auth=on_auth) self.agent.connect() def share_dir(self, dir_to_share, perms=None): dir_to_share = os.path.expanduser(dir_to_share) dir_to_share = utils.unfuck_path(dir_to_share) workspace_name = os.path.basename(dir_to_share) G.PROJECT_PATH = os.path.realpath(dir_to_share) msg.debug('%s %s %s' % (G.USERNAME, workspace_name, G.PROJECT_PATH)) if os.path.isfile(dir_to_share): return msg.error('%s is a file. Give me a directory please.' % dir_to_share) try: utils.mkdir(dir_to_share) except Exception: return msg.error("The directory %s doesn't exist and I can't make it." % dir_to_share) floo_file = os.path.join(dir_to_share, '.floo') info = {} try: floo_info = open(floo_file, 'rb').read().decode('utf-8') info = json.loads(floo_info) except (IOError, OSError): pass except Exception: msg.debug("Couldn't read the floo_info file: %s" % floo_file) workspace_url = info.get('url') if workspace_url: try: result = utils.parse_url(workspace_url) except Exception as e: msg.error(str(e)) else: workspace_name = result['workspace'] try: # TODO: blocking. beachballs sublime 2 if API is super slow api.get_workspace_by_url(workspace_url) except HTTPError: workspace_url = None workspace_name = os.path.basename(dir_to_share) else: utils.add_workspace_to_persistent_json(result['owner'], result['workspace'], workspace_url, dir_to_share) workspace_url = utils.get_workspace_by_path(dir_to_share) or workspace_url if workspace_url: try: api.get_workspace_by_url(workspace_url) except HTTPError: pass else: return self.remote_connect(workspace_url, lambda this: this.protocol.create_buf(dir_to_share)) def on_done(data, choices=None): self.create_workspace({}, workspace_name, dir_to_share, owner=data.get('response'), perms=perms) orgs = api.get_orgs_can_admin() orgs = json.loads(orgs.read().decode('utf-8')) if len(orgs) == 0: return on_done({'response': G.USERNAME}) i = 0 choices = [] choices.append([G.USERNAME, i]) for o in orgs: i += 1 choices.append([o['name'], i]) self.get_input('Create workspace for [press tab for completion]: ', '', on_done, choices=choices) def create_workspace(self, data, workspace_name, dir_to_share, owner=None, perms=None): owner = owner or G.USERNAME workspace_name = data.get('response', workspace_name) prompt = 'workspace %s already exists. Choose another name: ' % workspace_name try: api_args = { 'name': workspace_name, 'owner': owner, } if perms: api_args['perms'] = perms api.create_workspace(api_args) workspace_url = utils.to_workspace_url({'secure': True, 'owner': owner, 'workspace': workspace_name}) msg.debug('Created workspace %s' % workspace_url) except HTTPError as e: err_body = e.read() msg.error('Unable to create workspace: %s %s' % (unicode(e), err_body)) if e.code not in [400, 402, 409]: return msg.error('Unable to create workspace: %s' % str(e)) if e.code == 400: workspace_name = re.sub('[^A-Za-z0-9_\-]', '-', workspace_name) prompt = 'Invalid name. Workspace names must match the regex [A-Za-z0-9_\-]. Choose another name:' elif e.code == 402: try: err_body = json.loads(err_body) err_body = err_body['detail'] except Exception: pass return sublime.error_message('%s' % err_body) else: prompt = 'Workspace %s/%s already exists. Choose another name:' % (owner, workspace_name) return self.get_input(prompt, workspace_name, self.create_workspace, workspace_name, dir_to_share, owner, perms) except Exception as e: return msg.error('Unable to create workspace: %s' % str(e)) G.PROJECT_PATH = dir_to_share self.remote_connect(workspace_url, lambda this: this.protocol.create_buf(dir_to_share)) def join_workspace(self, data, owner, workspace, dir_to_make=None): d = data['response'] workspace_url = utils.to_workspace_url({'secure': True, 'owner': owner, 'workspace': workspace}) if dir_to_make: if d: d = dir_to_make utils.mkdir(d) else: d = '' if d == '': return self.get_input('Give me a directory to sync data to: ', G.PROJECT_PATH, self.join_workspace, owner, workspace) d = os.path.realpath(os.path.expanduser(d)) if not os.path.isdir(d): if dir_to_make: return msg.error("Couldn't create directory %s" % dir_to_make) prompt = '%s is not a directory. Create it? ' % d return self.get_input(prompt, '', self.join_workspace, owner, workspace, dir_to_make=d, y_or_n=True) try: G.PROJECT_PATH = d utils.mkdir(os.path.dirname(G.PROJECT_PATH)) self.remote_connect(workspace_url) except Exception as e: return msg.error("Couldn't create directory %s: %s" % (G.PROJECT_PATH, str(e))) def handle(self, req): self.net_buf += req while True: before, sep, after = self.net_buf.partition('\n') if not sep: break self.net_buf = after try: data = json.loads(before) except Exception as e: msg.error('Unable to parse json:', e) msg.error('Data:', before) raise e if data['name'] == 'share_dir': utils.reload_settings() G.USERNAME = data['username'] G.SECRET = data['secret'] self.share_dir(data['dir_to_share'], data.get('perms')) elif data['name'] == 'join_workspace': utils.reload_settings() workspace = data['workspace'] owner = data['workspace_owner'] G.USERNAME = data['username'] G.SECRET = data['secret'] try: G.PROJECT_PATH = utils.get_persistent_data()['workspaces'][owner][workspace]['path'] except Exception: G.PROJECT_PATH = '' if G.PROJECT_PATH and os.path.isdir(G.PROJECT_PATH): workspace_url = utils.to_workspace_url({'secure': True, 'owner': owner, 'workspace': workspace}) self.remote_connect(workspace_url) continue G.PROJECT_PATH = '~/floobits/share/%s/%s' % (owner, workspace) self.get_input('Give me a directory to sync data to: ', G.PROJECT_PATH, self.join_workspace, owner, workspace) elif data['name'] == 'user_input': cb_id = int(data['id']) cb = self.user_inputs.get(cb_id) if cb is None: msg.error('cb for input %s is none' % cb_id) continue cb(data) del self.user_inputs[cb_id] else: self.agent.protocol.emacs_handle(data) def put(self, name, data): data['name'] = name self.to_emacs_q.append(json.dumps(data) + '\n') def reconnect(self): try: self.conn.shutdown(socket.SHUT_RDWR) self.conn.close() except Exception: pass self.sock.close() sys.exit(1) def select(self): if not self.conn: msg.error('select(): No socket.') return self.reconnect() while True: if self.agent: self.agent.tick() out_conns = [] if len(self.to_emacs_q) > 0: out_conns.append(self.conn) try: _in, _out, _except = select.select([self.conn], out_conns, [self.conn], 0.05) except (select.error, socket.error, Exception) as e: msg.error('Error in select(): %s' % str(e)) return self.reconnect() if _except: msg.error('Socket error') return self.reconnect() if _in: buf = '' while True: try: d = self.conn.recv(4096) if not d: break buf += d except (socket.error, TypeError): break if buf: self.empty_selects = 0 self.handle(buf) else: self.empty_selects += 1 if self.empty_selects > 10: msg.error('No data from sock.recv() {0} times.'.format(self.empty_selects)) return self.reconnect() if _out: while len(self.to_emacs_q) > 0: p = self.to_emacs_q.pop(0) try: msg.debug('to emacs: %s' % p) self.conn.sendall(p) except Exception as e: msg.error('Couldn\'t write to socket: %s' % str(e)) return self.reconnect()