diff --git a/main.py b/main.py index 48810d4..91abc9e 100644 --- a/main.py +++ b/main.py @@ -71,18 +71,20 @@ from matrix.completion import ( matrix_olm_user_completion_cb, matrix_olm_device_completion_cb, matrix_user_completion_cb) -from matrix.utils import (key_from_value, server_buffer_prnt, prnt_debug, +from matrix.utils import (key_from_value, server_buffer_prnt, server_buffer_set_title) -from matrix.plugin_options import (DebugType, RedactType) +from matrix.config import ( + matrix_config_reload_cb, + MatrixConfig, + config_log_level_cb, + config_log_category_cb, + config_server_buffer_cb +) -from matrix.config import (matrix_config_init, matrix_config_read, - matrix_config_free, matrix_config_change_cb, - matrix_config_reload_cb) +from matrix import globals as G -import matrix.globals - -from matrix.globals import W, SERVERS, SCRIPT_NAME, OPTIONS +from matrix.globals import W, SERVERS, SCRIPT_NAME # yapf: disable WEECHAT_SCRIPT_NAME = SCRIPT_NAME @@ -415,7 +417,10 @@ def room_close_cb(data, buffer): @utf8_decode def matrix_unload_cb(): - matrix_config_free(matrix.globals.CONFIG) + for server in SERVERS.values(): + server.config.free() + + G.CONFIG.free() # for server in SERVERS.values(): # server.store_olm() @@ -430,7 +435,7 @@ def autoconnect(servers): def debug_buffer_close_cb(data, buffer): - OPTIONS.debug_buffer_ptr = "" + G.CONFIG.debug_buffer = "" return W.WEECHAT_RC_OK @@ -450,12 +455,12 @@ class WeechatHandler(StreamHandler): def write(self, item): buf = "" - if OPTIONS.debug_buffer: - if not OPTIONS.debug_buffer_ptr: - OPTIONS.debug_buffer_ptr = W.buffer_new( + if G.CONFIG.network.debug_buffer: + if not G.CONFIG.debug_buffer: + G.CONFIG.debug_buffer = W.buffer_new( "Matrix Debug", "", "", "debug_buffer_close_cb", "") - buf = OPTIONS.debug_buffer_ptr + buf = G.CONFIG.debug_buffer W.prnt(buf, item) @@ -475,16 +480,14 @@ if __name__ == "__main__": handler.push_application() # TODO if this fails we should abort and unload the script. - matrix.globals.CONFIG = W.config_new("matrix", - "matrix_config_reload_cb", "") - matrix_config_init(matrix.globals.CONFIG) - matrix_config_read(matrix.globals.CONFIG) + G.CONFIG = MatrixConfig() + G.CONFIG.read() hook_commands() init_bar_items() init_completion() if not SERVERS: - create_default_server(matrix.globals.CONFIG) + create_default_server(G.CONFIG) autoconnect(SERVERS) diff --git a/matrix/buffer.py b/matrix/buffer.py index 72126fa..e8928e1 100644 --- a/matrix/buffer.py +++ b/matrix/buffer.py @@ -22,7 +22,8 @@ from builtins import super from functools import partial from typing import NamedTuple -from .globals import W, SERVERS, OPTIONS, SCRIPT_NAME +from . import globals as G +from .globals import W, SERVERS, SCRIPT_NAME from .utf import utf8_decode from .colors import Formatted from .utils import ( @@ -30,7 +31,7 @@ from .utils import ( server_ts_to_weechat, string_strikethrough, ) -from .plugin_options import RedactType +from .config import RedactType from nio import ( Api, @@ -128,7 +129,7 @@ class RoomUser(WeechatUser): def __init__(self, nick, user_id=None, power_level=0, join_time=None): # type: (str, str, int) -> None prefix = self._get_prefix(power_level) - return super().__init__(nick, user_id, prefix, join_time) + super().__init__(nick, user_id, prefix, join_time) @property def power_level(self): @@ -922,12 +923,12 @@ class RoomBuffer(object): new_message = "" - if OPTIONS.redaction_type == RedactType.STRIKETHROUGH: + if G.CONFIG.look.redaction_type == RedactType.STRIKETHROUGH: plaintext_msg = W.string_remove_color(message, '') new_message = string_strikethrough(plaintext_msg) - elif OPTIONS.redaction_type == RedactType.NOTICE: + elif G.CONFIG.look.redaction_type == RedactType.NOTICE: new_message = message - elif OPTIONS.redaction_type == RedactType.DELETE: + elif G.CONFIG.look.redaction_type == RedactType.DELETE: pass message = " ".join(s for s in [new_message, redaction_msg] if s) diff --git a/matrix/colors.py b/matrix/colors.py index 322197f..730ec27 100644 --- a/matrix/colors.py +++ b/matrix/colors.py @@ -21,7 +21,8 @@ from __future__ import unicode_literals # pylint: disable=redefined-builtin from builtins import str from collections import namedtuple -from matrix.globals import W, OPTIONS +from matrix import globals as G +from matrix.globals import W from matrix.utils import string_strikethrough import re @@ -53,12 +54,9 @@ class Formatted(): def textwrapper(self): return textwrap.TextWrapper( width=67, - initial_indent="{}> ".format( - W.color(W.config_string(OPTIONS.options["quote"])) - ), - subsequent_indent="{}> ".format( - W.color(W.config_string(OPTIONS.options["quote"])) - )) + initial_indent="{}> ".format(G.CONFIG.color.quote), + subsequent_indent="{}> ".format(G.CONFIG.color.quote) + ) def is_formatted(self): # type: (Formatted) -> bool diff --git a/matrix/commands.py b/matrix/commands.py index 51b2707..280149e 100644 --- a/matrix/commands.py +++ b/matrix/commands.py @@ -21,7 +21,7 @@ import re import argparse import matrix.globals -from matrix.globals import W, OPTIONS, SERVERS +from matrix.globals import W, SERVERS from matrix.utf import utf8_decode from matrix.utils import key_from_value, tags_from_line_data @@ -661,7 +661,7 @@ def matrix_server_command_listfull(args): W.prnt("", message) - option = server.config.options["autoconnect"] + option = server.config._option_ptrs["autoconnect"] default_value = W.config_string_default(option) value = W.config_string(option) @@ -670,7 +670,7 @@ def matrix_server_command_listfull(args): W.prnt("", message) - option = server.config.options["address"] + option = server.config._option_ptrs["address"] default_value = W.config_string_default(option) value = W.config_string(option) @@ -679,7 +679,7 @@ def matrix_server_command_listfull(args): W.prnt("", message) - option = server.config.options["port"] + option = server.config._option_ptrs["port"] default_value = str(W.config_integer_default(option)) value = str(W.config_integer(option)) @@ -688,7 +688,7 @@ def matrix_server_command_listfull(args): W.prnt("", message) - option = server.config.options["username"] + option = server.config._option_ptrs["username"] default_value = W.config_string_default(option) value = W.config_string(option) @@ -697,7 +697,7 @@ def matrix_server_command_listfull(args): W.prnt("", message) - option = server.config.options["password"] + option = server.config._option_ptrs["password"] value = W.config_string(option) if value: @@ -732,7 +732,7 @@ def matrix_server_command_delete(args): if server.server_buffer: W.buffer_close(server.server_buffer) - for option in server.config.options.values(): + for option in server.config._option_ptrs.values(): W.config_option_free(option) message = ("matrix: server {color}{server}{ncolor} has been " @@ -762,7 +762,7 @@ def matrix_server_command_add(args): return def remove_server(server): - for option in server.config.options.values(): + for option in server.config._option_ptrs.values(): W.config_option_free(option) del SERVERS[server.name] @@ -788,7 +788,7 @@ def matrix_server_command_add(args): host, port = args[1], None return_code = W.config_option_set( - server.config.options["address"], + server.config._option_ptrs["address"], host, 1 ) @@ -809,7 +809,7 @@ def matrix_server_command_add(args): if port: return_code = W.config_option_set( - server.config.options["port"], + server.config._option_ptrs["port"], port, 1 ) @@ -830,7 +830,7 @@ def matrix_server_command_add(args): if len(args) >= 3: user = args[2] return_code = W.config_option_set( - server.config.options["username"], + server.config._option_ptrs["username"], user, 1 ) @@ -853,7 +853,7 @@ def matrix_server_command_add(args): password = args[3] return_code = W.config_option_set( - server.config.options["password"], + server.config._option_ptrs["password"], password, 1 ) diff --git a/matrix/completion.py b/matrix/completion.py index a15d9d2..ce5c471 100644 --- a/matrix/completion.py +++ b/matrix/completion.py @@ -17,7 +17,7 @@ from __future__ import unicode_literals from matrix.utf import utf8_decode -from matrix.globals import W, SERVERS, OPTIONS +from matrix.globals import W, SERVERS from matrix.utils import tags_from_line_data @@ -82,6 +82,10 @@ def matrix_debug_completion_cb(data, completion_item, buffer, completion): return W.WEECHAT_RC_OK +# TODO this should be configurable +REDACTION_COMP_LEN = 50 + + @utf8_decode def matrix_message_completion_cb(data, completion_item, buffer, completion): own_lines = W.hdata_pointer(W.hdata_get('buffer'), buffer, 'own_lines') @@ -103,8 +107,8 @@ def matrix_message_completion_cb(data, completion_item, buffer, completion): if (message and 'matrix_message' in tags and 'matrix_redacted' not in tags): - if len(message) > OPTIONS.redaction_comp_len + 2: - message = (message[:OPTIONS.redaction_comp_len] + '..') + if len(message) > REDACTION_COMP_LEN + 2: + message = (message[:REDACTION_COMP_LEN] + '..') item = ("{number}:\"{message}\"").format( number=line_number, message=message) diff --git a/matrix/config.py b/matrix/config.py index 3382049..06b9c4a 100644 --- a/matrix/config.py +++ b/matrix/config.py @@ -14,18 +14,83 @@ # CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from __future__ import unicode_literals +# from __future__ import unicode_literals +from builtins import super import nio import logbook -from matrix.plugin_options import (Option, RedactType, ServerBufferType) - -import matrix.globals -from matrix.globals import W, OPTIONS, SERVERS +from . import globals as G +from matrix.globals import W, SERVERS, SCRIPT_NAME from matrix.utf import utf8_decode -from matrix.utils import key_from_value, server_buffer_merge -from matrix.commands import hook_page_up + +from enum import Enum, unique +from collections import namedtuple + + +@unique +class RedactType(Enum): + STRIKETHROUGH = 0 + NOTICE = 1 + DELETE = 2 + + +@unique +class ServerBufferType(Enum): + MERGE_CORE = 0 + MERGE = 1 + INDEPENDENT = 2 + + +@unique +class DebugType(Enum): + MESSAGING = 0 + NETWORK = 1 + TIMING = 2 + + +class Option(namedtuple( + 'Option', + [ + 'name', + 'type', + 'string_values', + 'min', + 'max', + 'value', + 'description', + 'cast_func', + 'change_callback' + ] +)): + __slots__ = () + + def __new__( + cls, + name, + type, + string_values, + min, + max, + value, + description, + cast=None, + change_callback=None + ): + return super().__new__( + cls, + name, + type, + string_values, + min, + max, + value, + description, + cast, + change_callback + ) + + @utf8_decode @@ -47,148 +112,220 @@ def change_log_level(category, level): @utf8_decode -def matrix_config_change_cb(data, option): - option_name = key_from_value(OPTIONS.options, option) - - if option_name == "redactions": - OPTIONS.redaction_type = RedactType(W.config_integer(option)) - - elif option_name == "server_buffer": - OPTIONS.look_server_buf = ServerBufferType(W.config_integer(option)) - for server in SERVERS.values(): - if server.server_buffer: - server_buffer_merge(server.server_buffer) - - elif option_name == "max_initial_sync_events": - OPTIONS.sync_limit = W.config_integer(option) - - elif option_name == "max_backlog_sync_events": - OPTIONS.backlog_limit = W.config_integer(option) - - elif option_name == "debug_level": - value = W.config_integer(option) - if value == 0: - OPTIONS.debug_level = logbook.ERROR - elif value == 1: - OPTIONS.debug_level = logbook.WARNING - elif value == 2: - OPTIONS.debug_level = logbook.INFO - elif value == 3: - OPTIONS.debug_level = logbook.DEBUG - - change_log_level(OPTIONS.debug_category, OPTIONS.debug_level) - - elif option_name == "debug_category": - value = W.config_integer(option) - change_log_level(OPTIONS.debug_category, logbook.ERROR) - - if value == 0: - OPTIONS.debug_category = "all" - elif value == 1: - OPTIONS.debug_category = "http" - elif value == 2: - OPTIONS.debug_category = "client" - elif value == 3: - OPTIONS.debug_category = "events" - elif value == 4: - OPTIONS.debug_category = "responses" - - change_log_level(OPTIONS.debug_category, OPTIONS.debug_level) - - elif option_name == "debug_buffer": - OPTIONS.debug_buffer = W.config_boolean(option) - - elif option_name == "fetch_backlog_on_pgup": - OPTIONS.enable_backlog = W.config_boolean(option) - - if OPTIONS.enable_backlog: - if not OPTIONS.page_up_hook: - hook_page_up(matrix.globals.CONFIG) - else: - if OPTIONS.page_up_hook: - W.unhook(OPTIONS.page_up_hook) - OPTIONS.page_up_hook = None - +def config_server_buffer_cb(data, option): + for server in SERVERS.values(): + server.buffer_merge() return 1 -def matrix_config_init(config_file): - look_options = [ - Option("redactions", "integer", "strikethrough|notice|delete", 0, 0, - "strikethrough", - ("Only notice redactions, strike through or delete " - "redacted messages")), - Option("server_buffer", "integer", - "merge_with_core|merge_without_core|independent", 0, 0, - "merge_with_core", "Merge server buffers") - ] - - network_options = [ - Option("max_initial_sync_events", "integer", "", 1, 10000, "30", - ("How many events to fetch during the initial sync")), - Option("max_backlog_sync_events", "integer", "", 1, 100, "10", - ("How many events to fetch during backlog fetching")), - Option("fetch_backlog_on_pgup", "boolean", "", 0, 0, "on", - ("Fetch messages in the backlog on a window page up event")), - Option("debug_level", "integer", "error|warn|info|debug", 0, 0, - "off", "Enable network protocol debugging."), - Option("debug_category", "integer", "all|http|client|events|responses", - 0, 0, "all", "Debugging category"), - Option("debug_buffer", "boolean", "", 0, 0, "off", - ("Use a separate buffer for debug logs.")), - ] - - color_options = [ - Option("quote", "color", "", 0, 0, "lightgreen", - ("Color for matrix style blockquotes")) - ] - - def add_global_options(section, options): - for option in options: - OPTIONS.options[option.name] = W.config_new_option( - config_file, section, option.name, option.type, - option.description, option.string_values, option.min, - option.max, option.value, option.value, 0, "", "", - "matrix_config_change_cb", "", "", "") - - section = W.config_new_section(config_file, "color", 0, 0, "", "", "", "", - "", "", "", "", "", "") - - add_global_options(section, color_options) - - section = W.config_new_section(config_file, "look", 0, 0, "", "", "", "", - "", "", "", "", "", "") - - add_global_options(section, look_options) - - section = W.config_new_section(config_file, "network", 0, 0, "", "", "", - "", "", "", "", "", "", "") - - add_global_options(section, network_options) - - W.config_new_section( - config_file, "server", 0, 0, "matrix_config_server_read_cb", "", - "matrix_config_server_write_cb", "", "", "", "", "", "", "") - - return config_file +@utf8_decode +def config_log_level_cb(data, option): + change_log_level( + G.CONFIG.network.debug_category, + G.CONFIG.network.debug_level + ) + return 1 -def matrix_config_read(config): - # type: (str) -> bool - return_code = W.config_read(config) - if return_code == W.WEECHAT_CONFIG_READ_OK: - return True - elif return_code == W.WEECHAT_CONFIG_READ_MEMORY_ERROR: +@utf8_decode +def config_log_category_cb(data, option): + change_log_level(G.CONFIG.debug_category, logbook.ERROR) + G.CONFIG.debug_category = G.CONFIG.network.debug_category + change_log_level( + G.CONFIG.network.debug_category, + G.CONFIG.network.debug_level + ) + return 1 + + +def level_to_logbook(value): + if value == 0: + return logbook.ERROR + elif value == 1: + return logbook.WARNING + elif value == 2: + return logbook.INFO + elif value == 3: + return logbook.DEBUG + + return logbook.ERROR + + +def logbook_category(value): + if value == 0: + return "all" + elif value == 1: + return "http" + elif value == 2: + return "client" + elif value == 3: + return "events" + elif value == 4: + return "responses" + + return "all" + + +class WeechatConfig(object): + def __init__(self, sections): + self._ptr = W.config_new( + SCRIPT_NAME, + SCRIPT_NAME + "_config_reload_cb", + "" + ) + + for section in sections: + name, options = section + section_class = ConfigSection.build(name, options) + setattr(self, name, section_class(name, self._ptr, options)) + + def free(self): + for section in [getattr(self, a) for a in dir(self) if + isinstance(getattr(self, a), ConfigSection)]: + section.free() + + W.config_free(self._ptr) + + def read(self): + return_code = W.config_read(self._ptr) + if return_code == W.WEECHAT_CONFIG_READ_OK: + return True + elif return_code == W.WEECHAT_CONFIG_READ_MEMORY_ERROR: + return False + elif return_code == W.WEECHAT_CONFIG_READ_FILE_NOT_FOUND: + return True return False - elif return_code == W.WEECHAT_CONFIG_READ_FILE_NOT_FOUND: - return True - return False -def matrix_config_free(config): - for section in ["network", "look", "color", "server"]: - section_pointer = W.config_search_section(config, section) - W.config_section_free_options(section_pointer) - W.config_section_free(section_pointer) +class ConfigSection(object): + @classmethod + def build(cls, name, options): + def constructor(self, name, config_ptr, options): + self._ptr = W.config_new_section(config_ptr, name, 0, 0, "", "", + "", "", "", "", "", "", "", "") + self._config_ptr = config_ptr + self._option_ptrs = {} - W.config_free(config) + for option in options: + self._add_option(option) + + attributes = { + option.name: cls.option_property( + option.name, + option.type, + cast_func=option.cast_func + ) for option in options + } + attributes["__init__"] = constructor + + section_class = type( + name.title() + "Section", + (cls,), + attributes + ) + return section_class + + def free(self): + W.config_section_free_options(self._ptr) + W.config_section_free(self._ptr) + + def _add_option(self, option): + cb = option.change_callback.__name__ if option.change_callback else "" + option_ptr = W.config_new_option( + self._config_ptr, self._ptr, option.name, option.type, + option.description, option.string_values, option.min, + option.max, option.value, option.value, 0, "", "", + cb, "", "", "") + + self._option_ptrs[option.name] = option_ptr + + @staticmethod + def option_property(name, option_type, evaluate=False, cast_func=None): + def bool_getter(self): + return bool(W.config_boolean(self._option_ptrs[name])) + + def str_getter(self): + return W.config_string(self._option_ptrs[name]) + + def str_evaluate_getter(self): + return W.string_eval_expression( + W.config_string(self._option_ptrs[name]), + {}, + {}, + {} + ) + + def int_getter(self): + if cast_func: + return cast_func(W.config_integer(self._option_ptrs[name])) + else: + return W.config_integer(self._option_ptrs[name]) + + if option_type == "string" or option_type == "color": + if evaluate: + return property(str_evaluate_getter) + return property(str_getter) + elif option_type == "boolean": + return property(bool_getter) + elif option_type == "integer": + return property(int_getter) + + +class MatrixConfig(WeechatConfig): + def __init__(self): + + self.debug_buffer = "" + self.debug_category = "all" + + look_options = [ + Option("redactions", "integer", "strikethrough|notice|delete", 0, + 0, "strikethrough", + ("Only notice redactions, strike through or delete " + "redacted messages"), RedactType), + Option("server_buffer", "integer", + "merge_with_core|merge_without_core|independent", 0, 0, + "merge_with_core", "Merge server buffers", ServerBufferType, + config_server_buffer_cb) + ] + + network_options = [ + Option("max_initial_sync_events", "integer", "", 1, 10000, "30", + ("How many events to fetch during the initial sync")), + Option("max_backlog_sync_events", "integer", "", 1, 100, "10", + ("How many events to fetch during backlog fetching")), + Option("fetch_backlog_on_pgup", "boolean", "", 0, 0, "on", + ("Fetch messages in the backlog on a window page up event") + ), + Option("debug_level", "integer", "error|warn|info|debug", 0, 0, + "error", "Enable network protocol debugging.", + level_to_logbook, config_log_level_cb), + Option("debug_category", "integer", + "all|http|client|events|responses", + 0, 0, "all", "Debugging category", logbook_category), + Option("debug_buffer", "boolean", "", 0, 0, "off", + ("Use a separate buffer for debug logs.")), + ] + + color_options = [ + Option("quote", "color", "", 0, 0, "lightgreen", + ("Color for matrix style blockquotes")) + ] + + sections = [ + ("network", network_options), + ("look", look_options), + ("color", color_options) + ] + + super().__init__(sections) + + # The server section is essentially a section with subsections and no + # options, handle that case independently. + W.config_new_section( + self._ptr, "server", 0, 0, "matrix_config_server_read_cb", "", + "matrix_config_server_write_cb", "", "", "", "", "", "", "") + + def free(self): + section_ptr = W.config_search_section(self._ptr, 'server') + W.config_section_free(section_ptr) + super().free() diff --git a/matrix/globals.py b/matrix/globals.py index efca89e..db3f7d4 100644 --- a/matrix/globals.py +++ b/matrix/globals.py @@ -19,7 +19,6 @@ from __future__ import unicode_literals import sys from matrix.utf import WeechatWrapper -from matrix.plugin_options import PluginOptions try: import weechat @@ -28,8 +27,7 @@ except ImportError: import matrix._weechat as weechat W = weechat -OPTIONS = PluginOptions() # type: PluginOptions SERVERS = dict() # type: Dict[str, MatrixServer] -CONFIG = None # type: weechat.config +CONFIG = None # type: MatrixConfig ENCRYPTION = True # type: bool SCRIPT_NAME = "matrix" # type: str diff --git a/matrix/plugin_options.py b/matrix/plugin_options.py deleted file mode 100644 index 7fbd9a6..0000000 --- a/matrix/plugin_options.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright © 2018 Damir Jelić -# -# Permission to use, copy, modify, and/or distribute this software for -# any purpose with or without fee is hereby granted, provided that the -# above copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY -# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER -# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF -# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -from __future__ import unicode_literals - -import logbook - -from collections import namedtuple -from enum import Enum, unique - - -@unique -class RedactType(Enum): - STRIKETHROUGH = 0 - NOTICE = 1 - DELETE = 2 - - -@unique -class ServerBufferType(Enum): - MERGE_CORE = 0 - MERGE = 1 - INDEPENDENT = 2 - - -@unique -class DebugType(Enum): - MESSAGING = 0 - NETWORK = 1 - TIMING = 2 - - -Option = namedtuple( - 'Option', - ['name', 'type', 'string_values', 'min', 'max', 'value', 'description']) - - -class PluginOptions: - - def __init__(self): - self.redaction_type = RedactType.STRIKETHROUGH # type: RedactType - self.look_server_buf = ServerBufferType.MERGE_CORE \ - # type: ServerBufferType - - self.sync_limit = 30 # type: int - self.backlog_limit = 10 # type: int - self.enable_backlog = True # type: bool - self.page_up_hook = None # type: weechat.hook - - self.redaction_comp_len = 50 # type: int - - self.options = dict() # type: Dict[str, weechat.config_option] - self.debug = [] - self.debug_level = logbook.ERROR - self.debug_category = "all" - self.debug_buffer = False - self.debug_buffer_ptr = "" diff --git a/matrix/server.py b/matrix/server.py index 50e81a1..ba7a215 100644 --- a/matrix/server.py +++ b/matrix/server.py @@ -29,18 +29,18 @@ from nio import ( LoginResponse, SyncRepsponse, RoomSendResponse, - RoomPutStateResponse, TransportResponse, TransportType, LocalProtocolError ) -from matrix.plugin_options import Option, DebugType -from matrix.utils import (key_from_value, prnt_debug, server_buffer_prnt, +from matrix.utils import (key_from_value, server_buffer_prnt, create_server_buffer) from matrix.utf import utf8_decode -from matrix.globals import W, SERVERS, SCRIPT_NAME, OPTIONS +from . import globals as G +from matrix.globals import W, SERVERS, SCRIPT_NAME from .buffer import RoomBuffer, OwnMessage, OwnAction +from .config import Option, ServerBufferType, ConfigSection try: FileNotFoundError @@ -48,29 +48,12 @@ except NameError: FileNotFoundError = IOError -class ServerConfig(object): - def option_property(name, option_type): - def bool_getter(self): - return bool(W.config_boolean(self.options[name])) - - def str_getter(self): - return W.config_string(self.options[name]) - - def int_getter(self): - return W.config_integer(self.options[name]) - - if option_type == str: - return property(str_getter) - elif option_type == bool: - return property(bool_getter) - elif option_type == int: - return property(int_getter) - +class ServerConfig(ConfigSection): def __init__(self, server_name, config_ptr): # type: (str, str) -> None self._server_name = server_name - self._ptr = config_ptr - self.options = {} + self._config_ptr = config_ptr + self._option_ptrs = {} options = [ Option('autoconnect', 'boolean', '', 0, 0, 'off', @@ -95,37 +78,33 @@ class ServerConfig(object): ] section = W.config_search_section(config_ptr, 'server') + self._ptr = section for option in options: option_name = "{server}.{option}".format( server=self._server_name, option=option.name) - self.options[option.name] = W.config_new_option( + self._option_ptrs[option.name] = W.config_new_option( config_ptr, section, option_name, option.type, option.description, option.string_values, option.min, option.max, option.value, option.value, 0, "", "", "matrix_config_server_change_cb", self._server_name, "", "") - def _get_str_option(self, option_name): - return W.config_string(self.options[option_name]) + autoconnect = ConfigSection.option_property("autoconnect", "boolean") + address = ConfigSection.option_property("address", "string") + port = ConfigSection.option_property("port", "integer") + proxy = ConfigSection.option_property("proxy", "string") + ssl_verify = ConfigSection.option_property("ssl_verify", "boolean") + username = ConfigSection.option_property("username", "string") + device_name = ConfigSection.option_property("device_name", "string") + password = ConfigSection.option_property( + "password", + "string", + evaluate=True + ) - autoconnect = option_property("autoconnect", bool) - address = option_property("address", str) - port = option_property("port", int) - proxy = option_property("proxy", str) - ssl_verify = option_property("ssl_verify", bool) - username = option_property("username", str) - device_name = option_property("device_name", str) - - @property - def password(self): - # type: () -> str - return W.string_eval_expression( - self._get_str_option("password"), - {}, - {}, - {} - ) + def free(self): + W.config_section_free_options(self._ptr) class MatrixServer(object): @@ -609,7 +588,13 @@ class MatrixServer(object): # self.store_olm() # self.upload_keys(device_keys=True, one_time_keys=False) - sync_filter = {"room": {"timeline": {"limit": OPTIONS.sync_limit}}} + sync_filter = { + "room": { + "timeline": { + "limit": G.CONFIG.network.max_initial_sync_events + } + } + } self.sync(timeout=0, filter=sync_filter) def _handle_room_info(self, response): @@ -718,6 +703,35 @@ class MatrixServer(object): room_buffer = self.room_buffers[room_id] return room_buffer + def buffer_merge(self): + if not self.server_buffer: + return + + buf = self.server_buffer + + if G.CONFIG.look.server_buffer == ServerBufferType.MERGE_CORE: + num = W.buffer_get_integer(W.buffer_search_main(), "number") + W.buffer_unmerge(buf, num + 1) + W.buffer_merge(buf, W.buffer_search_main()) + elif G.CONFIG.look.server_buffer == ServerBufferType.MERGE: + if SERVERS: + first = None + for server in SERVERS.values(): + if server.server_buffer: + first = server.server_buffer + break + if first: + num = W.buffer_get_integer( + W.buffer_search_main(), + "number" + ) + W.buffer_unmerge(buf, num + 1) + if buf is not first: + W.buffer_merge(buf, first) + else: + num = W.buffer_get_integer(W.buffer_search_main(), "number") + W.buffer_unmerge(buf, num + 1) + @utf8_decode def matrix_config_server_read_cb(data, config_file, section, option_name, @@ -736,9 +750,9 @@ def matrix_config_server_read_cb(data, config_file, section, option_name, SERVERS[server.name] = server # Ignore invalid options - if option in server.config.options: + if option in server.config._option_ptrs: return_code = W.config_option_set( - server.config.options[option], + server.config._option_ptrs[option], value, 1 ) @@ -754,7 +768,7 @@ def matrix_config_server_write_cb(data, config_file, section_name): return W.WECHAT_CONFIG_WRITE_ERROR for server in SERVERS.values(): - for option in server.config.options.values(): + for option in server.config._option_ptrs.values(): if not W.config_write_option(config_file, option): return W.WECHAT_CONFIG_WRITE_ERROR @@ -770,7 +784,7 @@ def matrix_config_server_change_cb(server_name, option): # The function config_option_get_string() is used to get differing # properties from a config option, sadly it's only available in the plugin # API of weechat. - option_name = key_from_value(server.config.options, option) + option_name = key_from_value(server.config._option_ptrs, option) server.update_option(option, option_name) return 1 @@ -807,11 +821,6 @@ def matrix_timer_cb(server_name, remaining_calls): while server.send_queue: message = server.send_queue.popleft() - prnt_debug( - DebugType.MESSAGING, - server, ("Timer hook found message of type {t} in queue. Sending " - "out.".format(t=message.__class__.__name__))) - if not server.send(message): # We got an error while sending the last message return the message # to the queue and exit the loop @@ -835,7 +844,7 @@ def matrix_timer_cb(server_name, remaining_calls): def create_default_server(config_file): - server = MatrixServer('matrix_org', config_file) + server = MatrixServer('matrix_org', config_file._ptr) SERVERS[server.name] = server option = W.config_get(SCRIPT_NAME + ".server." + server.name + ".address") diff --git a/matrix/utils.py b/matrix/utils.py index 3f3662b..7172b4e 100644 --- a/matrix/utils.py +++ b/matrix/utils.py @@ -20,9 +20,8 @@ from builtins import str import time import math -from matrix.globals import W, SERVERS, OPTIONS - -from matrix.plugin_options import ServerBufferType +from matrix import globals as G +from matrix.globals import W, SERVERS try: from urlparse import urlparse @@ -35,11 +34,6 @@ def key_from_value(dictionary, value): return list(dictionary.keys())[list(dictionary.values()).index(value)] -def prnt_debug(debug_type, server, message): - if debug_type in OPTIONS.debug: - W.prnt(server.server_buffer, message) - - def server_buffer_prnt(server, string): # type: (MatrixServer, str) -> None assert server.server_buffer @@ -79,29 +73,7 @@ def create_server_buffer(server): W.buffer_set(server.server_buffer, "localvar_set_server", server.name) W.buffer_set(server.server_buffer, "localvar_set_channel", server.name) - server_buffer_merge(server.server_buffer) - - -def server_buffer_merge(buffer): - if OPTIONS.look_server_buf == ServerBufferType.MERGE_CORE: - num = W.buffer_get_integer(W.buffer_search_main(), "number") - W.buffer_unmerge(buffer, num + 1) - W.buffer_merge(buffer, W.buffer_search_main()) - elif OPTIONS.look_server_buf == ServerBufferType.MERGE: - if SERVERS: - first = None - for server in SERVERS.values(): - if server.server_buffer: - first = server.server_buffer - break - if first: - num = W.buffer_get_integer(W.buffer_search_main(), "number") - W.buffer_unmerge(buffer, num + 1) - if buffer is not first: - W.buffer_merge(buffer, first) - else: - num = W.buffer_get_integer(W.buffer_search_main(), "number") - W.buffer_unmerge(buffer, num + 1) + server.buffer_merge() def server_buffer_set_title(server):