93 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			93 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
| #!/usr/bin/env python3
 | |
| import sys
 | |
| import os
 | |
| import logging
 | |
| import argparse
 | |
| import json
 | |
| import unicodedata
 | |
| 
 | |
| sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'api'))
 | |
| import zulip
 | |
| 
 | |
| def write_public_streams() -> None:
 | |
|     public_streams = set()
 | |
| 
 | |
|     for stream_name in stream_names:
 | |
|         # Zephyr class names are canonicalized by first applying NFKC
 | |
|         # normalization and then lower-casing server-side
 | |
|         canonical_cls = unicodedata.normalize("NFKC", stream_name).lower()
 | |
|         if canonical_cls in ['security', 'login', 'network', 'ops', 'user_locate',
 | |
|                              'mit', 'moof', 'wsmonitor', 'wg_ctl', 'winlogger',
 | |
|                              'hm_ctl', 'hm_stat', 'zephyr_admin', 'zephyr_ctl']:
 | |
|             # These zephyr classes cannot be subscribed to by us, due
 | |
|             # to MIT's Zephyr access control settings
 | |
|             continue
 | |
| 
 | |
|         public_streams.add(canonical_cls)
 | |
| 
 | |
|     with open("/home/zulip/public_streams.tmp", "w") as f:
 | |
|         f.write(json.dumps(list(public_streams)) + "\n")
 | |
|     os.rename("/home/zulip/public_streams.tmp", "/home/zulip/public_streams")
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     log_file = "/home/zulip/sync_public_streams.log"
 | |
|     logger = logging.getLogger(__name__)
 | |
|     log_format = "%(asctime)s: %(message)s"
 | |
|     logging.basicConfig(format=log_format)
 | |
|     formatter = logging.Formatter(log_format)
 | |
|     logger.setLevel(logging.DEBUG)
 | |
|     file_handler = logging.FileHandler(log_file)
 | |
|     file_handler.setFormatter(formatter)
 | |
|     logger.addHandler(file_handler)
 | |
| 
 | |
|     parser = zulip.add_default_arguments(argparse.ArgumentParser())
 | |
|     options = parser.parse_args()
 | |
| 
 | |
|     zulip_client = zulip.Client(client="ZulipSyncPublicStreamsBot/0.1")
 | |
|     backoff = zulip.RandomExponentialBackoff()
 | |
| 
 | |
|     while backoff.keep_going():
 | |
|         try:
 | |
|             res = zulip_client.register(event_types=["stream"])
 | |
|             if res["result"] != "success":
 | |
|                 backoff.fail()
 | |
|                 logger.error("Error registering event queue:\n%r", res)
 | |
|                 continue
 | |
|         except Exception:
 | |
|             logger.exception("Error registering event queue:")
 | |
|             continue
 | |
| 
 | |
|         backoff.succeed()
 | |
|         queue_id = res["queue_id"]
 | |
|         last_event_id = res["last_event_id"]
 | |
|         stream_names = {stream["name"] for stream in res["streams"]}
 | |
|         write_public_streams()
 | |
| 
 | |
|         while backoff.keep_going():
 | |
|             try:
 | |
|                 res = zulip_client.get_events(queue_id=queue_id, last_event_id=last_event_id)
 | |
|                 if res["result"] != "success":
 | |
|                     backoff.fail()
 | |
|                     logger.error("Error getting events:\n%r", res)
 | |
|                     if res["result"] == "error":
 | |
|                         # Break out to the outer loop to re-register the event queue.
 | |
|                         break
 | |
|                     continue
 | |
|             except Exception:
 | |
|                 logger.exception("Error getting events:")
 | |
|                 continue
 | |
| 
 | |
|             backoff.succeed()
 | |
|             for event in res["events"]:
 | |
|                 last_event_id = max(last_event_id, event["id"])
 | |
|                 if event["type"] == "stream":
 | |
|                     if event["op"] == "create":
 | |
|                         stream_names.update(
 | |
|                             stream["name"] for stream in event["streams"]
 | |
|                         )
 | |
|                         write_public_streams()
 | |
|                     elif event["op"] == "delete":
 | |
|                         stream_names.difference_update(
 | |
|                             stream["name"] for stream in event["streams"]
 | |
|                         )
 | |
|                         write_public_streams()
 | 
