mirror of
				https://github.com/9001/copyparty.git
				synced 2025-11-04 05:43:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			137 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			137 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python
 | 
						|
# coding: utf-8
 | 
						|
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
 | 
						|
from __future__ import print_function, unicode_literals
 | 
						|
 | 
						|
import json
 | 
						|
import os
 | 
						|
import sys
 | 
						|
import time
 | 
						|
 | 
						|
try:
 | 
						|
    from datetime import datetime, timezone
 | 
						|
except:
 | 
						|
    from datetime import datetime
 | 
						|
 | 
						|
 | 
						|
_ = r"""
 | 
						|
use copyparty as a dumb messaging server / guestbook thing;
 | 
						|
accepts guestbook entries from 📟 (message-to-server-log) in the web-ui
 | 
						|
initially contributed by @clach04 in https://github.com/9001/copyparty/issues/35 (thanks!)
 | 
						|
 | 
						|
example usage as global config:
 | 
						|
    python copyparty-sfx.py --xm j,bin/hooks/msg-log.py
 | 
						|
 | 
						|
parameters explained,
 | 
						|
    xm = execute on message (📟)
 | 
						|
    j  = this hook needs message information as json (not just the message-text)
 | 
						|
 | 
						|
example usage as a volflag (per-volume config):
 | 
						|
    python copyparty-sfx.py -v srv/log:log:r:c,xm=j,bin/hooks/msg-log.py
 | 
						|
                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
						|
 | 
						|
    (share filesystem-path srv/log as volume /log, readable by everyone,
 | 
						|
     running this plugin on all messages with the params explained above)
 | 
						|
 | 
						|
example usage as a volflag in a copyparty config file:
 | 
						|
    [/log]
 | 
						|
      srv/log
 | 
						|
      accs:
 | 
						|
        r: *
 | 
						|
      flags:
 | 
						|
        xm: j,bin/hooks/msg-log.py
 | 
						|
"""
 | 
						|
 | 
						|
 | 
						|
# output filename
 | 
						|
FILENAME = os.environ.get("COPYPARTY_MESSAGE_FILENAME", "") or "README.md"
 | 
						|
 | 
						|
# set True to write in descending order (newest message at top of file);
 | 
						|
# note that this becomes very slow/expensive as the file gets bigger
 | 
						|
DESCENDING = True
 | 
						|
 | 
						|
# the message template; the following parameters are provided by copyparty and can be referenced below:
 | 
						|
# 'ap' = absolute filesystem path where the message was posted
 | 
						|
# 'vp' = virtual path (URL 'path') where the message was posted
 | 
						|
# 'mt' = 'at' = unix-timestamp when the message was posted
 | 
						|
# 'datetime' = ISO-8601 time when the message was posted
 | 
						|
# 'sz' = message size in bytes
 | 
						|
# 'host' = the server hostname which the user was accessing (URL 'host')
 | 
						|
# 'user' = username (if logged in), otherwise '*'
 | 
						|
# 'txt' = the message text itself
 | 
						|
# (uncomment the print(msg_info) to see if additional information has been introduced by copyparty since this was written)
 | 
						|
TEMPLATE = """
 | 
						|
🕒 %(datetime)s, 👤 %(user)s @ %(ip)s
 | 
						|
%(txt)s
 | 
						|
"""
 | 
						|
 | 
						|
 | 
						|
def write_ascending(filepath, msg_text):
 | 
						|
    with open(filepath, "a", encoding="utf-8", errors="replace") as outfile:
 | 
						|
        outfile.write(msg_text)
 | 
						|
 | 
						|
 | 
						|
def write_descending(filepath, msg_text):
 | 
						|
    lockpath = filepath + ".lock"
 | 
						|
    got_it = False
 | 
						|
    for _ in range(16):
 | 
						|
        try:
 | 
						|
            os.mkdir(lockpath)
 | 
						|
            got_it = True
 | 
						|
            break
 | 
						|
        except:
 | 
						|
            time.sleep(0.1)
 | 
						|
            continue
 | 
						|
 | 
						|
    if not got_it:
 | 
						|
        return sys.exit(1)
 | 
						|
 | 
						|
    try:
 | 
						|
        oldpath = filepath + ".old"
 | 
						|
        os.rename(filepath, oldpath)
 | 
						|
        with open(oldpath, "r", encoding="utf-8", errors="replace") as infile, open(
 | 
						|
            filepath, "w", encoding="utf-8", errors="replace"
 | 
						|
        ) as outfile:
 | 
						|
            outfile.write(msg_text)
 | 
						|
            while True:
 | 
						|
                buf = infile.read(4096)
 | 
						|
                if not buf:
 | 
						|
                    break
 | 
						|
                outfile.write(buf)
 | 
						|
    finally:
 | 
						|
        try:
 | 
						|
            os.unlink(oldpath)
 | 
						|
        except:
 | 
						|
            pass
 | 
						|
        os.rmdir(lockpath)
 | 
						|
 | 
						|
 | 
						|
def main(argv=None):
 | 
						|
    if argv is None:
 | 
						|
        argv = sys.argv
 | 
						|
 | 
						|
    msg_info = json.loads(sys.argv[1])
 | 
						|
    # print(msg_info)
 | 
						|
 | 
						|
    try:
 | 
						|
        dt = datetime.fromtimestamp(msg_info["at"], timezone.utc)
 | 
						|
    except:
 | 
						|
        dt = datetime.utcfromtimestamp(msg_info["at"])
 | 
						|
 | 
						|
    msg_info["datetime"] = dt.strftime("%Y-%m-%d, %H:%M:%S")
 | 
						|
 | 
						|
    msg_text = TEMPLATE % msg_info
 | 
						|
 | 
						|
    filepath = os.path.join(msg_info["ap"], FILENAME)
 | 
						|
 | 
						|
    if DESCENDING and os.path.exists(filepath):
 | 
						|
        write_descending(filepath, msg_text)
 | 
						|
    else:
 | 
						|
        write_ascending(filepath, msg_text)
 | 
						|
 | 
						|
    print(msg_text)
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    main()
 |