weechat-matrix/matrix/config.py

484 lines
13 KiB
Python
Raw Normal View History

2018-01-26 14:38:46 +01:00
# -*- coding: utf-8 -*-
# Copyright © 2018 Damir Jelić <poljar@termina.org.uk>
#
# 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.
2018-08-29 15:35:36 +02:00
from builtins import super
2018-08-29 19:40:59 +02:00
from collections import namedtuple
from enum import Enum, unique
2018-01-26 14:38:46 +01:00
2018-07-24 11:05:03 +02:00
import logbook
2018-08-30 16:35:05 +02:00
import nio
2018-08-29 19:40:59 +02:00
from matrix.globals import SCRIPT_NAME, SERVERS, W
2018-01-29 17:47:47 +01:00
from matrix.utf import utf8_decode
2018-08-29 15:35:36 +02:00
2018-08-29 19:40:59 +02:00
from . import globals as G
2018-08-29 15:35:36 +02:00
@unique
class RedactType(Enum):
STRIKETHROUGH = 0
NOTICE = 1
DELETE = 2
@unique
class ServerBufferType(Enum):
MERGE_CORE = 0
MERGE = 1
INDEPENDENT = 2
nio.logger_group.level = logbook.ERROR
2018-08-29 19:40:59 +02:00
class Option(
namedtuple(
"Option",
[
"name",
"type",
"string_values",
"min",
"max",
"value",
"description",
"cast_func",
"change_callback",
],
)
):
2018-08-29 15:35:36 +02:00
__slots__ = ()
def __new__(
cls,
name,
type,
string_values,
min,
max,
value,
description,
cast=None,
2018-08-29 19:40:59 +02:00
change_callback=None,
2018-08-29 15:35:36 +02:00
):
return super().__new__(
cls,
name,
type,
string_values,
min,
max,
value,
description,
cast,
2018-08-29 19:40:59 +02:00
change_callback,
2018-08-29 15:35:36 +02:00
)
2018-01-29 17:47:47 +01:00
@utf8_decode
def matrix_config_reload_cb(data, config_file):
return W.WEECHAT_RC_OK
2018-07-24 11:05:03 +02:00
def change_log_level(category, level):
if category == "all":
nio.logger_group.level = level
elif category == "http":
nio.http.logger.level = level
elif category == "client":
nio.client.logger.level = level
elif category == "events":
nio.events.logger.level = level
elif category == "responses":
nio.responses.logger.level = level
2018-09-15 23:27:43 +02:00
elif category == "encryption":
nio.encryption.logger.level = level
2018-07-24 11:05:03 +02:00
2018-01-29 17:47:47 +01:00
@utf8_decode
2018-08-29 15:35:36 +02:00
def config_server_buffer_cb(data, option):
for server in SERVERS.values():
server.buffer_merge()
2018-01-29 17:47:47 +01:00
return 1
2018-08-29 15:35:36 +02:00
@utf8_decode
def config_log_level_cb(data, option):
change_log_level(
2018-08-29 19:40:59 +02:00
G.CONFIG.network.debug_category, G.CONFIG.network.debug_level
2018-08-29 15:35:36 +02:00
)
return 1
2018-01-29 17:47:47 +01:00
2018-08-29 15:35:36 +02:00
@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(
2018-08-29 19:40:59 +02:00
G.CONFIG.network.debug_category, G.CONFIG.network.debug_level
2018-08-29 15:35:36 +02:00
)
return 1
2018-01-29 17:47:47 +01:00
2018-09-03 20:39:16 +02:00
@utf8_decode
def config_pgup_cb(data, option):
if G.CONFIG.network.fetch_backlog_on_pgup:
if not G.CONFIG.page_up_hook:
G.CONFIG.page_up_hook = W.hook_command_run(
"/window page_up", "matrix_command_pgup_cb", ""
)
else:
if G.CONFIG.page_up_hook:
W.unhook(G.CONFIG.page_up_hook)
G.CONFIG.page_up_hook = None
return 1
2018-08-29 15:35:36 +02:00
def level_to_logbook(value):
if value == 0:
return logbook.ERROR
2018-08-29 19:40:59 +02:00
if value == 1:
2018-08-29 15:35:36 +02:00
return logbook.WARNING
2018-08-29 19:40:59 +02:00
if value == 2:
2018-08-29 15:35:36 +02:00
return logbook.INFO
2018-08-29 19:40:59 +02:00
if value == 3:
2018-08-29 15:35:36 +02:00
return logbook.DEBUG
return logbook.ERROR
def logbook_category(value):
if value == 0:
return "all"
2018-08-29 19:40:59 +02:00
if value == 1:
2018-08-29 15:35:36 +02:00
return "http"
2018-08-29 19:40:59 +02:00
if value == 2:
2018-08-29 15:35:36 +02:00
return "client"
2018-08-29 19:40:59 +02:00
if value == 3:
2018-08-29 15:35:36 +02:00
return "events"
2018-08-29 19:40:59 +02:00
if value == 4:
2018-08-29 15:35:36 +02:00
return "responses"
2018-09-15 23:27:43 +02:00
if value == 5:
return "encryption"
2018-08-29 15:35:36 +02:00
return "all"
class WeechatConfig(object):
def __init__(self, sections):
self._ptr = W.config_new(
2018-08-29 19:40:59 +02:00
SCRIPT_NAME, SCRIPT_NAME + "_config_reload_cb", ""
2018-08-29 15:35:36 +02:00
)
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):
2018-08-29 19:40:59 +02:00
for section in [
getattr(self, a)
for a in dir(self)
if isinstance(getattr(self, a), ConfigSection)
]:
2018-08-29 15:35:36 +02:00
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
2018-08-29 19:40:59 +02:00
if return_code == W.WEECHAT_CONFIG_READ_MEMORY_ERROR:
2018-08-29 15:35:36 +02:00
return False
2018-08-29 19:40:59 +02:00
if return_code == W.WEECHAT_CONFIG_READ_FILE_NOT_FOUND:
2018-08-29 15:35:36 +02:00
return True
2018-01-29 17:47:47 +01:00
return False
2018-08-29 15:35:36 +02:00
class ConfigSection(object):
@classmethod
def build(cls, name, options):
def constructor(self, name, config_ptr, options):
2018-08-29 19:40:59 +02:00
self._ptr = W.config_new_section(
config_ptr, name, 0, 0, "", "", "", "", "", "", "", "", "", ""
)
2018-08-29 15:35:36 +02:00
self._config_ptr = config_ptr
self._option_ptrs = {}
for option in options:
self._add_option(option)
attributes = {
option.name: cls.option_property(
2018-08-29 19:40:59 +02:00
option.name, option.type, cast_func=option.cast_func
)
for option in options
2018-08-29 15:35:36 +02:00
}
attributes["__init__"] = constructor
2018-08-29 19:40:59 +02:00
section_class = type(name.title() + "Section", (cls,), attributes)
2018-08-29 15:35:36 +02:00
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(
2018-08-29 19:40:59 +02:00
self._config_ptr,
self._ptr,
option.name,
option.type,
option.description,
option.string_values,
option.min,
option.max,
option.value,
option.value,
0,
"",
"",
cb,
"",
"",
"",
)
2018-08-29 15:35:36 +02:00
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(
2018-08-29 19:40:59 +02:00
W.config_string(self._option_ptrs[name]), {}, {}, {}
2018-08-29 15:35:36 +02:00
)
def int_getter(self):
if cast_func:
return cast_func(W.config_integer(self._option_ptrs[name]))
2018-08-29 19:40:59 +02:00
return W.config_integer(self._option_ptrs[name])
2018-08-29 15:35:36 +02:00
2018-08-29 19:40:59 +02:00
if option_type in ("string", "color"):
2018-08-29 15:35:36 +02:00
if evaluate:
return property(str_evaluate_getter)
return property(str_getter)
2018-08-29 19:40:59 +02:00
if option_type == "boolean":
2018-08-29 15:35:36 +02:00
return property(bool_getter)
2018-08-29 19:40:59 +02:00
if option_type == "integer":
2018-08-29 15:35:36 +02:00
return property(int_getter)
class MatrixConfig(WeechatConfig):
def __init__(self):
self.debug_buffer = ""
self.debug_category = "all"
2018-08-29 19:40:59 +02:00
self.page_up_hook = None
2018-08-29 15:35:36 +02:00
look_options = [
2018-08-29 19:40:59 +02:00
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,
),
Option(
"max_typing_notice_item_length",
"integer",
"",
10,
1000,
"50",
("Limit the length of the typing notice bar item."),
),
Option(
"bar_item_typing_notice_prefix",
"string",
"",
0,
0,
"Typing: ",
("Prefix for the typing notice bar item."),
),
2018-08-29 15:35:36 +02:00
]
network_options = [
2018-08-29 19:40:59 +02:00
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"),
2018-09-03 20:39:16 +02:00
None,
config_pgup_cb,
2018-08-29 19:40:59 +02:00
),
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",
2018-09-15 23:27:43 +02:00
"all|http|client|events|responses|encryption",
2018-08-29 19:40:59 +02:00
0,
0,
"all",
"Debugging category",
logbook_category,
config_log_category_cb,
2018-08-29 19:40:59 +02:00
),
Option(
"debug_buffer",
"boolean",
"",
0,
0,
"off",
("Use a separate buffer for debug logs."),
),
Option(
"lazy_load_room_users",
"boolean",
"",
0,
0,
"off",
("If on, room users wont be loaded background proactively "
"they will be loaded when the buffer becomes active. This "
"only affects non encrypted rooms."),
),
Option(
"max_nicklist_users",
"integer",
"",
100,
20000,
"5000",
("Limit the number of users that are added to the nicklist. "
"Active users and users with a higher power level are always."
" Inactive users will be removed from the nicklist after a "
"day of inactivity."),
),
Option(
"lag_reconnect",
"integer",
"",
5,
604800,
"90",
("Reconnect to the server if the lag is greater than this "
"value (in seconds)"),
),
2018-08-29 15:35:36 +02:00
]
color_options = [
2018-08-29 19:40:59 +02:00
Option(
"quote",
"color",
"",
0,
0,
"lightgreen",
("Color for matrix style blockquotes"),
)
2018-08-29 15:35:36 +02:00
]
sections = [
("network", network_options),
("look", look_options),
2018-08-29 19:40:59 +02:00
("color", color_options),
2018-08-29 15:35:36 +02:00
]
super().__init__(sections)
# The server section is essentially a section with subsections and no
# options, handle that case independently.
W.config_new_section(
2018-08-29 19:40:59 +02:00
self._ptr,
"server",
0,
0,
"matrix_config_server_read_cb",
"",
"matrix_config_server_write_cb",
"",
"",
"",
"",
"",
"",
"",
)
2018-08-29 15:35:36 +02:00
def free(self):
2018-08-29 19:40:59 +02:00
section_ptr = W.config_search_section(self._ptr, "server")
2018-08-29 15:35:36 +02:00
W.config_section_free(section_ptr)
super().free()