diff --git a/bin/comrad-cli b/bin/comrad-cli index d348ff3..2c1700c 100755 --- a/bin/comrad-cli +++ b/bin/comrad-cli @@ -12,5 +12,7 @@ path_repo="`realpath ~/comrad/code`" source $path_conda/etc/profile.d/conda.sh export PATH="$path_conda/bin:$PATH" conda activate $path_venv -python -m pip install -r $path_repo/requirements.txt -python $path_repo/comrad/cli/cli.py \ No newline at end of file +python -m pip install -r $path_repo/requirements.txt -q + +export COMRAD_SHOW_LOG=0 +python $path_repo/comrad/cli/cli.py $* \ No newline at end of file diff --git a/comrad/app/screens/feed/feed.py b/comrad/app/screens/feed/feed.py index 6e676c5..d1d7365 100644 --- a/comrad/app/screens/feed/feed.py +++ b/comrad/app/screens/feed/feed.py @@ -69,9 +69,9 @@ class PostAuthorLabel(MDLabel): # ''' def on_touch_down(self, touch): if self.collide_point(*touch.pos): - username=self.text.strip().split()[1][1:] + # username=self.text.strip().split()[1][1:] app=App.get_running_app() - app.view_profile(username) + app.view_profile(self.username) return True pass @@ -86,7 +86,8 @@ class PostTimestampLabel(MDLabel): class PostAuthorAvatar(AsyncImage): def on_touch_down(self, touch): if self.collide_point(*touch.pos): - print('wiiiiimg') + app=App.get_running_app() + app.view_profile(self.username) return True # stop pass @@ -147,13 +148,15 @@ class PostCard(MDCard): self.author_label.text+=f'\n[size={recip_label_font_size}]to '+recip+'[/size]' self.author_label.markup=True self.author_label.font_size = author_label_font_size - + self.author_label.username=self.author + avatar_img_src = os.path.join(PATH_AVATARS, f'{self.author}.png') if not os.path.exists(avatar_img_src): avatar_img_src = os.path.join(PATH_GUI_ASSETS, 'avatars', f'{self.author}.png') if not os.path.exists(avatar_img_src): avatar_img_src=PATH_DEFAULT_AVATAR self.author_avatar = author_avatar = PostAuthorAvatar(source=avatar_img_src) #self.img_src) + self.author_avatar.username=self.author self.author_section_layout.add_widget(author_avatar) self.author_section_layout.add_widget(author_label) # self.author_section_layout.add_widget(MDSeparator(height='1sp',size_hint=(None,None))) diff --git a/comrad/app/screens/profile/profile.py b/comrad/app/screens/profile/profile.py index 04676ee..4f601bb 100644 --- a/comrad/app/screens/profile/profile.py +++ b/comrad/app/screens/profile/profile.py @@ -33,7 +33,7 @@ class ProfileAvatar(Image): self.screen.carousel.index=0 anim = Animation(opacity=1, duration=0.1) anim.start(start) - else: + elif self.screen.app.username == self.screen.app.comrad.name: self.choose() def choose(self): @@ -307,37 +307,48 @@ class ProfileScreen(ProtectedScreen): # self.author_info_layout.add_widget(self.author_name) - ## AUTHOR DESCRIPTION - self.author_desc = AuthorDesc(text='... etc ...') - self.author_desc.font_name='assets/font.otf' - self.author_desc.font_size='18sp' - # self.author_desc.halign='left' - - ## Pronouns - self.author_pronouns = AuthorPronouns(label='they/them',icon='gender-transgender') - - ## AUTHOR PLACE - self.author_place = AuthorPlace(label='Deterritorialized',icon='map-marker-outline') - - ## Website - self.author_website = AuthorWebsite(label='website.org', icon='link-variant') + # desc from us + if not self.app.comrad.exists_locally(self.app.username): + author_desc=f'Comrad @{self.app.username} is not a contact of yours.' + self.author_desc = AuthorDesc(text=author_desc) + self.author_desc.font_name='assets/font.otf' + self.author_desc.font_size='18sp' + self.author_info_layout.add_widget(self.author_desc) - - ## Followers - self.follower_layout = FollowerLayout() - # self.author_followers = AuthorFollowers(label='13 followers',icon='account-arrow-left') - self.author_following = AuthorFollowing(label='13 comrades',icon='account-multiple') - - - ## add to layout - self.author_info_layout.add_widget(self.author_desc) - self.author_info_layout.add_widget(self.author_pronouns) - self.author_info_layout.add_widget(self.author_place) - # self.author_info_layout.add_widget(self.author_website) - - self.follower_layout.add_widget(self.author_following) - # self.follower_layout.add_widget(self.author_followers) - self.author_info_layout.add_widget(self.follower_layout) + # this is a contact + else: + ## AUTHOR DESCRIPTION + author_desc=f'... etc ...' + self.author_desc = AuthorDesc(text=author_desc) + self.author_desc.font_name='assets/font.otf' + self.author_desc.font_size='18sp' + # self.author_desc.halign='left' + + ## Pronouns + self.author_pronouns = AuthorPronouns(label='they/them',icon='gender-transgender') + + ## AUTHOR PLACE + self.author_place = AuthorPlace(label='Deterritorialized',icon='map-marker-outline') + + ## Website + self.author_website = AuthorWebsite(label='website.org', icon='link-variant') + + + ## Followers + self.follower_layout = FollowerLayout() + # self.author_followers = AuthorFollowers(label='13 followers',icon='account-arrow-left') + self.author_following = AuthorFollowing(label='13 comrades',icon='account-multiple') + + + ## add to layout + self.author_info_layout.add_widget(self.author_desc) + self.author_info_layout.add_widget(self.author_pronouns) + self.author_info_layout.add_widget(self.author_place) + # self.author_info_layout.add_widget(self.author_website) + + self.follower_layout.add_widget(self.author_following) + # self.follower_layout.add_widget(self.author_followers) + self.author_info_layout.add_widget(self.follower_layout) # class AuthorPlace(MDLabel): pass # class AuthorWebsite(MDLabel): pass diff --git a/comrad/backend/comrades.py b/comrad/backend/comrades.py index 8084544..a422a01 100644 --- a/comrad/backend/comrades.py +++ b/comrad/backend/comrades.py @@ -64,12 +64,12 @@ class ComradX(Caller): # return self.register() - def exists_locally(self): - pubkey=self.find_pubkey() + def exists_locally(self,name=None): + pubkey=self.find_pubkey(name=name) return bool(pubkey) - def exists_locally_as_contact(self): - pubkey=self.find_pubkey() + def exists_locally_as_contact(self,name=None): + pubkey=self.find_pubkey(name=name) if not pubkey: return False uri=pubkey.data_b64 if self.crypt_keys.get(uri,prefix='/privkey_encr/'): @@ -77,9 +77,9 @@ class ComradX(Caller): self.log(pubkey,self.name,'???') return True - def exists_locally_as_account(self): + def exists_locally_as_account(self,name=None): #return bool(self.pubkey) and bool(self.privkey_encr) - pubkey=self.find_pubkey() + pubkey=self.find_pubkey(name=name) # self.log('found pubkey:',pubkey) if not pubkey: return False uri=pubkey.data_b64 @@ -102,7 +102,7 @@ class ComradX(Caller): ## Talking with Operator async def ring_ring(self,msg,route=None,**y): - logger.info('got here 2!') + # logger.info('got here 2!') if type(msg)==dict and not ROUTE_KEYNAME in msg: msg[ROUTE_KEYNAME]=route return await super().ring_ring(msg,caller=self,**y) @@ -379,7 +379,7 @@ class ComradX(Caller): ### MEETING PEOLPE - def meet(self,name=None,pubkey=None,returning=False): + async def meet(self,name=None,pubkey=None,returning=False): if not name and not pubkey: return {'success':False,'status':'Meet whom?'} @@ -406,7 +406,7 @@ class ComradX(Caller): } self.log('msg_to_op',msg_to_op) - res = self.ring_ring( + res = await self.ring_ring( msg_to_op, route='introduce' ) diff --git a/comrad/backend/mazes.py b/comrad/backend/mazes.py index 407bfe9..249ace5 100644 --- a/comrad/backend/mazes.py +++ b/comrad/backend/mazes.py @@ -43,7 +43,10 @@ class MazeWalker(Handler): # texec(f, router) # f(router) import asyncio - asyncio.run(f(router)) + try: + asyncio.run(f(router)) + except ValueError: + f(router) pass diff --git a/comrad/cli/cli.py b/comrad/cli/cli.py index 83a854a..361038e 100644 --- a/comrad/cli/cli.py +++ b/comrad/cli/cli.py @@ -1,7 +1,7 @@ import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__),'..')),'..'))) from comrad import * from comrad.backend import * -import art +import art,asyncio import textwrap as tw import readline,logging readline.set_completer_delims('\t') @@ -16,6 +16,7 @@ logging.getLogger('urllib3').propagate=False logging.getLogger('shapely').propagate=False logging.getLogger('pyproj').propagate=False logging.getLogger('rtree').propagate=False +logging.getLogger('asyncio').setLevel(logging.WARNING) torpy_logger.propagate=False from shutil import get_terminal_size @@ -110,6 +111,11 @@ class CLI(Logger): self.stat('Message not sent.',str(e),'\n') def stat(self,*msgs,use_prefix=True,prefix=None,comrad_name=None,pause=False,clear=False,min_prefix_len=12,**kwargs): + if hasattr(self,'_mapscr') and self._mapscr: + self._mapscr.endwin() + self._mapscr=None + self.hops = [] + if not prefix: if not comrad_name: comrad_name='Telephone' # prefix='Comrad @'+comrad_name+': ' @@ -122,6 +128,7 @@ class CLI(Logger): min_prefix_len=min_prefix_len if use_prefix and prefix else 0 ) print(total_msg) + # print() if pause: do_pause() if clear: clear_screen() @@ -255,17 +262,20 @@ class CLI(Logger): # mapscr.stdscr.getch() deets = self.ipinfo_handler.getDetails(rtr.ip) - self.hops.append((rtr,deets)) - places = [ - (_deets.city,tuple(float(_) for _ in _deets.loc.split(','))) - for (_rtr,_deets) in [(rtr,deets)] - ] + if rtr.ip not in {hop[0].ip for hop in self.hops}: + + self.hops.append((rtr,deets)) + places = [ + (_deets.city,tuple(float(_) for _ in _deets.loc.split(','))) + for (_rtr,_deets) in [(rtr,deets)] + ] - msg = ['@Tor: Hiding your IP by hopping it around the globe:'] + [f'{_deets.city}, {_deets.country_name} ({_rtr.nickname})' for _rtr,_deets in self.hops - ] - mapscr.run_print_map(places,msg=msg) - + + msg = ['@Tor: Hiding your IP by hopping it around the globe:'] + [f'{_deets.city}, {_deets.country_name} ({_rtr.nickname})' for _rtr,_deets in self.hops + ] + mapscr.run_print_map(places,msg=msg) + # self.stat( # msg, @@ -308,8 +318,29 @@ class CLI(Logger): # self.print(self,name,self.name,self.comrad,self.loggedin) if not name: name=input('name: ') if not name: return - self.comrad=Comrad(name,callbacks=self.callbacks) - return self.refresh() + self.comrad=commie=Comrad(name,callbacks=self.callbacks) + + if commie.exists_locally_as_account(): + from getpass import getpass + # pw=getpass(f'\n@Telephone: Welcome back. Your password please?\n@{name}: ') + pw=getpass(f'password: ') + commie.keychain(passphrase=pw) + self.log(f'updated keychain: {dict_format(commie.keychain())}') + self.log(f'is account') + # self.login_status.text='You should be able to log into this account.' + if commie.privkey: + self.log(f'passkey login succeeded') + self.stat(f'Welcome back, Comrad @{commie.name}') + self.loggedin=True + self.name=commie.name + self.help() + else: + logger.info(f'passkey login failed') + self.stat('Login failed...') + else: + self.stat('This is not an account of yours.') + + # return self.refresh() # res = self.comrad.login() # return self.do_login(res) @@ -352,7 +383,7 @@ class CLI(Logger): self.stat('Meet whom?') return name_or_pubkey = datl[0] - res = self.comrad.meet(name_or_pubkey,returning=returning) + res = asyncio.run(self.comrad.meet(name_or_pubkey,returning=returning)) status=res.get('status') self.stat(status) @@ -404,13 +435,16 @@ class CLI(Logger): ## get updates # this does login, msgs, and posts in one req time.sleep(0.25) - res = self.comrad.get_updates() + if not self.comrad: + self.stat('You must login first.') + + res = self.comrad.refresh() #print(res.get('success')) if not res.get('success'): self.stat(res.get('status'),comrad_name='') return - self.stat('@Telephone: Patching you through to the @Operator. One moment please...') + # self.stat('Patching you through to the @Operator. One moment please...') if hasattr(self,'_mapscr') and self._mapscr: #stop msg=self._mapscr.msg + ['???, ??? (@Operator)'] @@ -422,9 +456,9 @@ class CLI(Logger): self.log('<-- get_updates',res) # check logged in - res_login=res.get('res_login',{}) - if not self.do_login(res_login): return - self.stat('',res['status'],comrad_name='Operator',**statd) + # res_login=res.get('res_login',{}) + # if not self.do_login(res_login): return + # self.stat('',res['status'],comrad_name='Operator',**statd) return res @@ -475,7 +509,7 @@ class CLI(Logger): def prompt_msg(self,msg): clear_screen() print(msg) - self.stat('Type "r" to reply to this message, "d" to delete it, or hit Enter to continue.',use_prefix=False) + self.stat('Type "r" to reply to this message, "d" to delete it, hit Enter to continue, or type "q" to return to main menu.',use_prefix=False) do = input(f'\n{self.comrad}: ') do=do.strip().lower() if do=='d': @@ -489,6 +523,8 @@ class CLI(Logger): elif do=='r': # self.print('@todo: replying...') return self.dm(msg.from_name) + elif do=='q': + raise EOFError else: # seen this msg! self.comrad.seen_msg(msg) diff --git a/comrad/cli/worldmap_curses.py b/comrad/cli/worldmap_curses.py index 6233354..be2a988 100644 --- a/comrad/cli/worldmap_curses.py +++ b/comrad/cli/worldmap_curses.py @@ -251,6 +251,7 @@ class Map(Logger): def endwin(self): # time.sleep(1) curses.endwin() + self.hops=[] def do_print_map(self,places):