Commit 3444015e authored by Nick Yefremov's avatar Nick Yefremov

Updated redirector files, separated classes, updated setup

parent 2410da06
#!/usr/bin/env python
# -*- coding: utf-8 -*-
NAME = "redirector"
REDIRECTOR_DIR = "/var/lib/redirector"
MAPS_DIR = REDIRECTOR_DIR + "/maps"
CONFIG_DIR = REDIRECTOR_DIR + "/location-includes"
\ No newline at end of file
......@@ -2,9 +2,9 @@
class MapGenerator:
def __init__(self):
self.start_lines = [
"map $uri $%s-redirect {\n",
"\nmap $uri $%s-option-redirect {\n",
"\nmap $uri $%s-option {\n"
"map $uri $%s-redirect {",
"\nmap $uri $%s-option-redirect {",
"\nmap $uri $%s-option {"
]
self.endline = "\n}"
......@@ -13,17 +13,18 @@ class MapGenerator:
for i, map_type in enumerate(self.start_lines):
data += map_type % project_name
for arg1, arg2 in redirects_sorted[i]:
data += "\t%s\t%s;" % (arg1, arg2)
data += "\n\t%s\t%s;" % (arg1, arg2)
data += self.endline
return data
class ConfigGenerator:
def __init__(self):
self.start_line = "if($%s-redirect) {\n"
self.rewrite_line = "\trewrite ^/%s/(.^)$ %s redirect;\n}"
self.rewrite_line = "\trewrite ^/%s/(.^)$ $%s redirect;\n}"
def generate_conf(self, project_name):
return self.start_line % project_name + self.rewrite_line % project_name
return (self.start_line % project_name) + (self.rewrite_line % (project_name, project_name))
import logging
class Logger:
def __init__(self, file_=None):
if file_:
logging.basicConfig(filename=file_)
def log(self, message, level="critical"):
if self.file_:
if level == "critical":
logging.critical(message)
elif level == "debug":
logging.debug(message)
elif level == "info":
logging.info(message)
else:
print(level.upper() + ":\n" + message)
import sys
import yaml
from pprint import pprint as pp
import re
# Constants:
class RedirectorParser:
class MapLineParser:
def __init__(self, logger=None):
self.url_regexp = re.compile(r'(\/[(\w)-:]+)+\/?(\.\w+)?')
self.url_absolute = re.compile(r"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$")
self.url_absolute = re.compile(
r"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$")
self.logger = logger
def _parse_line(self, line, prefix, i):
if not line.startswith("#"):
line = line.split()
return_code, options = 0, []
if len(line) == 0:
return -1, None, None
elif len(line) < 2:
raise self.ParseLineError("Error on %s:{line};\nNot enough arguments to parse!".format(line=i), None)
elif len(line) > 2:
return_code = 1
options = [option[1:-1] for option in line[2:]]
# not url - regexp
if not self.url_regexp.fullmatch(line[0]):
try:
re.compile(line[0])
re.compile(line[1])
except re.error:
raise self.RegexpTestError("Can\'t compile regular expressions {expression1} {expression2} in "
"%s:{line_num}".format(expression1=line[0], expression2=line[1],
line_num=i), re.error)
# if new URI relative to the root
elif line[0].startswith("//"):
line[0] = line[0][1:] # cutting out extra '/' at the beginning
elif line[1].startswith("//"):
line[1] = line[1][1:]
elif self.url_absolute.fullmatch(line[1]):
pass
# default url
else:
line[0] = prefix + line[0]
line[1] = prefix + line[1]
return return_code, line[0], line[1], options
else:
def parse_line(self, line, prefix, i):
line = line.strip()
return_code, options = 0, []
if line.startswith("#") or len(line) == 0:
return -1, None, None
line = line.split()
if len(line) < 2:
raise self.ParseLineError("Error on %s:{line};\n"
"Not enough arguments to parse!".format(line=i), None)
elif len(line) > 2:
return_code = 1
options = [option[1:-1] for option in line[2:]]
if not self.url_regexp.fullmatch(line[0]): # not url - regexp
try:
re.compile(line[0])
re.compile(line[1])
except re.error:
raise self.RegexpTestError("Can\'t compile regular expressions {expression1} {expression2} in "
"%s:{line_num}".format(expression1=line[0], expression2=line[1],
line_num=i), re.error)
elif line[0].startswith("//"): # if new URI relative to the root
line[0] = line[0][1:] # cutting out extra '/' at the beginning
elif line[1].startswith("//"):
line[1] = line[1][1:]
elif self.url_absolute.fullmatch(line[1]):
pass
else: # default url
line[0] = prefix + line[0]
line[1] = prefix + line[1]
return return_code, line[0], line[1], options
class ParseLineError(Exception):
"""Raised when line contains not enough arguments
Attributes:
message -- expanation where in .yaml config file aprser didn't find enough arguments
"""
def __init__(self, message, errors):
super().__init__(message)
self.message = message
self.errors = errors
class RegexpTestError(Exception):
"""Raised when parser fails to compile url containing regular expression
Attributes:
message -- explanation what regexp failed to compile and where
"""
def __init__(self, message, errors):
super().__init__(message)
self.message = message
self.errors = errors
class ConfigReader:
def __init__(self, logger=None):
self.line_parser = MapLineParser(logger=logger)
if logger:
self.logger = logger
@staticmethod
def _parse_yaml(file_dir):
def parse_yaml(file_dir):
return_list = []
with open(file_dir, 'r') as stream:
data = yaml.safe_load(stream)
......@@ -59,34 +90,23 @@ class RedirectorParser:
return_list.append((map_path, project_prefix))
return return_list
def log(self, message, level="critical"):
if self.logger:
if level == "critical":
self.logger.critical(message)
elif level == "debug":
self.logger.debug(message)
elif level == "info":
self.logger.info(message)
else:
print(level.upper() + ":\n" + message)
def parse_map(self, map_file, yaml_file):
res = [[], [], []]
res_prefix = None
try:
for map_path, prefix in self._parse_yaml(yaml_file):
for map_path, prefix in self.parse_yaml(yaml_file):
if map_path == map_file:
# ???: Is the last directory of map_path a project's name?
res_prefix = prefix.split("/")[-1]
res_prefix = prefix.split("/")[-1] # ???: Is the last directory of map_path a project's name?
with open(map_file, "r") as file:
for i, line in enumerate(file):
request_url, redirect_url, options = None, None, []
try:
return_code, request_url, redirect_url, *options = self._parse_line(line, prefix, i)
except self.RegexpTestError as e:
self.log(e.message % map_file)
except self.ParseLineError as e:
self.log(e.message % map_file)
return_code, request_url, redirect_url, *options = \
self.line_parser.parse_line(line, prefix, i)
except MapLineParser.RegexpTestError as e:
self.logger.log(e.message % map_file)
except MapLineParser.ParseLineError as e:
self.logger.log(e.message % map_file)
if not request_url or not redirect_url or return_code == -1:
continue
......@@ -98,29 +118,5 @@ class RedirectorParser:
res[2].append((request_url, options))
return res, res_prefix
except yaml.YAMLError as e:
self.log("Error occured while reading %s" % yaml_file + str(e))
self.logger.log("Error occurred while reading %s" % yaml_file + str(e))
class ParseLineError(Exception):
"""Raised when line contains not enough arguments
Attributes:
message -- expanation where in .yaml config file aprser didn't find enough arguments
"""
def __init__(self, message, errors):
super().__init__(message)
self.message = message
self.errors = errors
class RegexpTestError(Exception):
"""Raised when parser fails to compile url containing regular expression
Attributes:
message -- explanation what regexp failed to compile and where
"""
def __init__(self, message, errors):
super().__init__(message)
self.message = message
self.errors = errors
import sys
import generators
import parser
import const
from core import generators
from core import logger
from core import parser
from core import const
class Redirector:
def __init__(self, logger=None):
self.parser = parser.RedirectorParser(logger=logger)
self.parser = parser.ConfigReader(logger=logger)
self.map_generator = generators.MapGenerator()
self.config_generator = generators.ConfigGenerator()
def log(self, message, level="critical"):
if self.logger:
if level == "critical":
self.logger.critical(message)
elif level == "debug":
self.logger.debug(message)
elif level == "info":
self.logger.info(message)
else:
print(level.upper() + ":\n" + message)
def generate(self, map_file, yaml_file):
def generate(self, yaml_file, map_file):
import pdb
pdb.set_trace()
project_name = "Error"
try:
data, project_name = self.parser.parse_map(map_file, yaml_file)
# FIXME: what is the better way to do so?
except Exception as e:
raise self.RedirectorParserError("Can\'t parse .map file %s" % map_file, e)
......@@ -35,10 +28,10 @@ class Redirector:
with open(const.CONFIG_DIR + "/%s.conf" % project_name, "w") as conf_file:
conf_file.write(self.config_generator.generate_conf(project_name))
except Exception as e:
print(e)
raise self.RedirectorGenerationError("Can\'t generate new .conf or new .map file \
from %s .map file for %s project" % (map_file, project_name). e)
from %s .map file for %s project" % (map_file, project_name), e)
class RedirectorParserError(Exception):
def __init__(self, message, errors):
super().__init__(message)
......
......@@ -5,10 +5,10 @@ setup(
name=const.NAME,
version="0.1",
packages=find_packages(),
entry_points="""
[redirector]
redirector = core.redirector:main
[redirector-watch]
redirector-watch = core.redirector:watch
"""
entry_points={
'console_scripts': [
'redirector = core.redirector:main',
'redirector-watch = core.redirector:watch'
]
}
)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment