Browse Source

code (re)organization. file upload.

now it must be installed with pip install .

also, forum/channel sorted by date.
boyska 4 years ago
parent
commit
f5413ab2ea
6 changed files with 173 additions and 141 deletions
  1. 0 30
      retroshare.py
  2. 14 111
      rscli/cli.py
  3. 14 0
      rscli/httputils.py
  4. 29 0
      rscli/retroshare.py
  5. 101 0
      rscli/rsfiles.py
  6. 15 0
      setup.py

+ 0 - 30
retroshare.py

@@ -1,30 +0,0 @@
-import enum  # py3.4
-
-try:
-    IntFlag = enum.IntFlag
-except AttributeError:
-    # requires py < 3.6
-    IntFlag = enum.Int
-
-class RS_FILE_HINTS(IntFlag):
-    CACHE_deprecated       = 0x00000001
-    EXTRA                  = 0x00000002
-    LOCAL                  = 0x00000004
-    REMOTE                 = 0x00000008
-    DOWNLOAD               = 0x00000010
-    UPLOAD                 = 0x00000020
-    SPEC_ONLY              = 0x01000000
-    NETWORK_WIDE           = 0x00000080
-
-    BROWSABLE              = 0x00000100
-    SEARCHABLE             = 0x00000200
-
-    PERMISSION_MASK        = 0x00000380
-
-
-
-# FileStorageFlags
-DIR_FLAGS_ANONYMOUS_DOWNLOAD = 0x0080
-DIR_FLAGS_BROWSABLE= 0x0400
-DIR_FLAGS_ANONYMOUS_SEARCH= 0x0800
-

+ 14 - 111
cli.py → rscli/cli.py

@@ -1,14 +1,11 @@
 #!/usr/bin/env python3
-import hashlib
 import sys
-import time
-import uuid
 from pprint import pprint
 import requests
 import argparse
-import os.path
 
-import retroshare
+from rscli import rsfiles
+from rscli.httputils import req
 
 try:
     from colors import color
@@ -17,30 +14,16 @@ except ImportError:
     def color(text, *args, **kwargs):
         return text
 
-try:
-    from fsdb import Fsdb
-except ImportError:
-    Fsdb = None
 
 
 def err(msg):
-    print(color(msg, fg='red', style='bold'))
+    print(color(msg, fg="red", style="bold"))
+
 
 def is_group_subscribed(mSubscribeFlags):
     return bool(mSubscribeFlags & 4)
 
 
-def req(args, location, data=None):
-    kwargs = {}
-    if data is not None:
-        kwargs["json"] = data
-    r = requests.post(
-        args.endpoint + location, auth=tuple(args.auth.split(":", 2)), **kwargs
-    )
-    r.raise_for_status()
-    # TODO: handle r.status_code != 200
-    return r
-
 
 def main_forum_list(args):
     r = req(args, "/rsGxsForums/getForumsSummaries")
@@ -61,6 +44,7 @@ def main_forum_list(args):
 def main_forum_read(args):
     r = req(args, "/rsGxsForums/getForumMsgMetaData", {"forumId": args.forum_id})
     items = r.json()["msgMetas"]
+    items.sort(key=lambda p: p['mPublishTs'], reverse=True)
     if args.long:
         msgs = [item["mMsgId"] for item in items[: args.num_posts]]
         items_r = req(
@@ -69,13 +53,14 @@ def main_forum_read(args):
             {"forumId": args.forum_id, "msgsIds": msgs},
         )
         items = items_r.json()["msgs"]
+        items.sort(key=lambda p: p['mMeta']['mPublishTs'], reverse=True)
         for item in items:
             print(color(item["mMeta"]["mMsgName"], style="bold", fg="green"))
             print()
             print(item["mMsg"])  # TODO: html2txt
             print()
     else:
-        for item in posts[: args.num_posts]:
+        for item in items[: args.num_posts]:
             print(color(item["mMsgName"], style="bold", fg="green"))
             print("   " + color(item["mMsgId"], style="underline"))
 
@@ -99,6 +84,7 @@ def main_channel_list(args):
 def main_channel_read(args):
     r = req(args, "/rsGxsChannels/getContentSummaries", {"channelId": args.channel_id})
     posts = r.json()["summaries"]
+    posts.sort(key=lambda p: p['mPublishTs'], reverse=True)
     if args.long:
         msgs = [post["mMsgId"] for post in posts[: args.num_posts]]
         posts_r = req(
@@ -107,6 +93,7 @@ def main_channel_read(args):
             {"channelId": args.channel_id, "contentsIds": msgs},
         )
         posts = posts_r.json()["posts"]
+        posts.sort(key=lambda p: p['mMeta']['mPublishTs'], reverse=True)
         for post in posts:
             print(color(post["mMeta"]["mMsgName"], style="bold", fg="green"))
             print()
@@ -130,7 +117,6 @@ def main_channel_show(args):
 
 
 def main_channel_post_v1(args):
-    chid = args.channel_id
     r = req(
         args,
         "/rsGxsChannels/createPost",
@@ -154,7 +140,6 @@ def main_channel_post_v1(args):
 
 
 def main_channel_post(args):
-    chid = args.channel_id
     try:
         r = req(
             args,
@@ -179,89 +164,13 @@ def main_channel_post(args):
     return main_channel_post_v1(args)
 
 
-def get_fsdb(args):
-    if Fsdb is None:
-        raise Exception('ERROR: library Fsdb is needed for file publishing')
-    store_dir = os.path.expanduser('~/.config/rscli/store/default')
-    return Fsdb(store_dir, fmode='660')
-
-def _file_publish(args, fnames):
-    fsdb = get_fsdb(args)
-    virtualname_path = os.path.join(fsdb.fsdbRoot, 'virtualname.txt')
-    if os.path.exists(virtualname_path):
-        virtualname = open(virtualname_path).read().strip()
-    else:
-        virtualname = 'rscli-%s' % uuid.uuid4()
-        open(virtualname_path, 'w').write(virtualname)
-    r = req(args, '/rsFiles/getSharedDirectories')
-    if virtualname not in [shared['virtualname'] for shared in r.json()['dirs']]:
-        r = req(args, '/rsFiles/addSharedDirectory', {'dir':{ 'filename': fsdb.fsdbRoot,
-                                                      'virtualname': virtualname
-                                                     }})
-        if not r.json()['retval']:
-            raise Exception("Error: could not create shared dir for default store")
-    r = req(args, '/rsFiles/getSharedDirectories')
-    dir_filename = [d['filename']
-                    for d in r.json()['dirs']
-                    if d['virtualname'] == virtualname][0]
-    r = req(args, '/rsFiles/requestDirDetails', { 'handle': 0 })
-    children = [c for c in r.json()['details']['children']
-                if c['name'] != '[Extra List]']
-    for possibile_root in children:
-        r = req(args, '/rsFiles/requestDirDetails',
-                { 'handle': possibile_root['handle'] })
-        found = [c for c in r.json()['details']['children']
-                 if c['name'] == dir_filename]
-        if not found:
-            raise Exception ('Error: could not find shared file in RS')
-        handle = found[0]['handle']
-
-    for fname in fnames:
-        digest = fsdb.add(fname)
-        # correct implementation: check hash inside storage
-        # unfortunately it is very slow because we can't give
-        # an hint to ForceDirectoryCheck for where to look
-        # for new files
-        # after the comment, there is a valid implementation, which has the defect 
-        # of being very coupled to retroshare implementation
-        # r = req(args, '/rsFiles/ForceDirectoryCheck')
-        #time.sleep(5)
-        ## mo lo ricerchiamo va
-        #looking_for = os.path.relpath(fsdb.get_file_path(digest),
-        #                              fsdb.fsdbRoot).split(os.path.sep)
-        #hashlib
-        #for next_component in looking_for:
-        #    r = req(args, '/rsFiles/requestDirDetails', { 'handle': handle })
-        #    found = [c for c in r.json()['details']['children']
-        #             if c['name'] == next_component]
-        #    if not found:
-        #        raise Exception('Error: could not find shared file in RS')
-        #    handle = found[0]['handle']
-        #r = req(args, '/rsFiles/requestDirDetails', { 'handle': handle })
-        #filehash = r.json()['details']['hash']
-        #yield filehash
-
-        h = hashlib.new('sha1')
-        h.update(open(fname, 'rb').read())
-        yield h.hexdigest()
-
-    r = req(args, '/rsFiles/ForceDirectoryCheck')
-
-def get_file_link(args, hash_digest, fname=None, size=None):
-    fsdb = get_fsdb(args)
-    if fname is None:
-        # TODO: check file name on filesystem
-        fname = os.path.basename(fsdb.get_file_path(hash_digest))
-    if size is None:
-        size = os.stat(fsdb.get_file_path(hash_digest)).st_size
-    return 'retroshare://file?name=%s&size=%d&hash=%s' % (fname, size, hash_digest)
-
 
 def main_file_publish(args):
-    ret = _file_publish(args, args.fnames)
+    ret = rsfiles.file_publish(args, args.fnames)
     for filehash, fname in zip(ret, args.fnames):
-        print(color(filehash, fg='green') + ' \t%s' % fname)
-        print('    ' + get_file_link(args, filehash, fname=fname))
+        print(color(filehash, fg="green") + " \t%s" % fname)
+        print("    " + rsfiles.get_file_link(args, filehash, fname=fname))
+
 
 def get_parser():
     p = argparse.ArgumentParser()
@@ -315,15 +224,9 @@ def get_parser():
     files = p_sub.add_parser("file")
     files_sub = files.add_subparsers()
     files_list = files_sub.add_parser("publish")
-    files_list.add_argument(
-        "--fname",
-        nargs="+",
-        required=True,
-        dest='fnames'
-    )
+    files_list.add_argument("--fname", nargs="+", required=True, dest="fnames")
     files_list.set_defaults(mainfunc=main_file_publish)
 
-
     # TODO: channel rss -> read and convert to rss
 
     return p

+ 14 - 0
rscli/httputils.py

@@ -0,0 +1,14 @@
+import requests
+
+def req(args, location, data=None):
+    kwargs = {}
+    if data is not None:
+        kwargs["json"] = data
+    r = requests.post(
+        args.endpoint + location, auth=tuple(args.auth.split(":", 2)), **kwargs
+    )
+    r.raise_for_status()
+    # TODO: handle r.status_code != 200
+    return r
+
+

+ 29 - 0
rscli/retroshare.py

@@ -0,0 +1,29 @@
+import enum  # py3.4
+
+try:
+    IntFlag = enum.IntFlag
+except AttributeError:
+    # requires py < 3.6
+    IntFlag = enum.Int
+
+
+class RS_FILE_HINTS(IntFlag):
+    CACHE_deprecated = 0x00000001
+    EXTRA = 0x00000002
+    LOCAL = 0x00000004
+    REMOTE = 0x00000008
+    DOWNLOAD = 0x00000010
+    UPLOAD = 0x00000020
+    SPEC_ONLY = 0x01000000
+    NETWORK_WIDE = 0x00000080
+
+    BROWSABLE = 0x00000100
+    SEARCHABLE = 0x00000200
+
+    PERMISSION_MASK = 0x00000380
+
+
+class DIR_FLAGS(IntFlag):
+    ANONYMOUS_DOWNLOAD = 0x0080
+    BROWSABLE = 0x0400
+    ANONYMOUS_SEARCH = 0x0800

+ 101 - 0
rscli/rsfiles.py

@@ -0,0 +1,101 @@
+import hashlib
+import time
+import uuid
+import os.path
+try:
+    from fsdb import Fsdb
+except ImportError:
+    Fsdb = None
+from rscli.httputils import req
+from rscli import retroshare
+
+
+def get_fsdb(args):
+    if Fsdb is None:
+        raise Exception("ERROR: library Fsdb is needed for file publishing")
+    store_dir = os.path.expanduser("~/.config/rscli/store/default")
+    return Fsdb(store_dir, fmode="660")
+
+
+def filename_to_hash(args, dir_virtualname, filename):
+    r = req(args, "/rsFiles/getSharedDirectories")
+    dir_filename = [
+        d["filename"] for d in r.json()["dirs"] if d["virtualname"] == dir_virtualname
+    ][0]
+    r = req(args, "/rsFiles/requestDirDetails", {"handle": 0})
+    children = [
+        c for c in r.json()["details"]["children"] if c["name"] != "[Extra List]"
+    ]
+    for possibile_root in children:
+        r = req(
+            args, "/rsFiles/requestDirDetails", {"handle": possibile_root["handle"]}
+        )
+        found = [
+            c for c in r.json()["details"]["children"] if c["name"] == dir_filename
+        ]
+        if not found:
+            raise Exception("Error: could not find shared file in RS")
+        handle = found[0]["handle"]
+
+    r = req(args, '/rsFiles/ForceDirectoryCheck')
+    time.sleep(5)
+    looking_for = filename.split(os.path.sep)
+    hashlib
+    for next_component in looking_for:
+       r = req(args, '/rsFiles/requestDirDetails', { 'handle': handle })
+       found = [c for c in r.json()['details']['children']
+                if c['name'] == next_component]
+       if not found:
+           raise Exception('Error: could not find shared file in RS')
+       handle = found[0]['handle']
+    r = req(args, '/rsFiles/requestDirDetails', { 'handle': handle })
+    filehash = r.json()['details']['hash']
+    return filehash
+
+
+def file_publish(args, fnames):
+    fsdb = get_fsdb(args)
+    virtualname_path = os.path.join(fsdb.fsdbRoot, "virtualname.txt")
+    if os.path.exists(virtualname_path):
+        virtualname = open(virtualname_path).read().strip()
+    else:
+        virtualname = "rscli-%s" % uuid.uuid4()
+        open(virtualname_path, "w").write(virtualname)
+
+    r = req(args, "/rsFiles/getSharedDirectories")
+    if virtualname not in [shared["virtualname"] for shared in r.json()["dirs"]]:
+        r = req(
+            args,
+            "/rsFiles/addSharedDirectory",
+            {
+                "dir": {
+                    "filename": fsdb.fsdbRoot,
+                    "virtualname": virtualname,
+                    "shareflags": retroshare.DIR_FLAGS.ANONYMOUS_DOWNLOAD,
+                }
+            },
+        )
+        if not r.json()["retval"]:
+            raise Exception("Error: could not create shared dir for default store")
+        time.sleep(1)
+
+    for fname in fnames:
+        fsdb.add(fname)
+        # print(filename_to_hash(args, virtualname, fsdb.get_file_path(digest)))
+
+        h = hashlib.new("sha1")
+        h.update(open(fname, "rb").read())
+        yield h.hexdigest()
+
+    r = req(args, "/rsFiles/ForceDirectoryCheck")
+
+
+def get_file_link(args, hash_digest, fname=None, size=None):
+    fsdb = get_fsdb(args)
+    if fname is None:
+        # TODO: check file name on filesystem
+        fname = os.path.basename(fsdb.get_file_path(hash_digest))
+    if size is None:
+        size = os.stat(fsdb.get_file_path(hash_digest)).st_size
+    return "retroshare://file?name=%s&size=%d&hash=%s" % (fname, size, hash_digest)
+

+ 15 - 0
setup.py

@@ -0,0 +1,15 @@
+from setuptools import setup
+
+setup(name='rscli',
+      version='0.1',
+      # description='The funniest joke in the world',
+      # url='http://github.com/storborg/funniest',
+      author='boyska',
+      author_email='',
+      license='AGPL3',
+      packages=['rscli'],
+
+      entry_points = {
+          'console_scripts': ['rscli=rscli.cli:main'],
+      },
+      zip_safe=False)