ichigogeta

cable_club_v19.py

Oct 1st, 2025
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 25.07 KB | None | 0 0
  1. import argparse
  2. import collections
  3. import configparser
  4. import csv
  5. import io
  6. import os.path
  7. import re
  8. import select
  9. import socket
  10. # MODIFICADO: Cambiado para usar la librería 'packaging' en lugar de la obsoleta 'distutils'
  11. from packaging.version import Version
  12. import logging
  13.  
  14. # This is the v19 version of the server. It is not compatible with earlier versions of the script
  15. # MODIFICADO: Adaptado para el sistema de multijugador en el mapa.
  16.  
  17. HOST = r"0.0.0.0"
  18. PORT = 9999
  19. PBS_DIR = r"./PBS"
  20. LOG_DIR = r"."
  21. RULES_DIR = "./OnlinePresets"
  22. # Aprox. in seconds
  23. RULES_REFRESH_RATE = 60
  24.  
  25. # MODIFICADO: Usando Version de 'packaging'
  26. GAME_VERSION = Version("1.0.0")
  27. POKEMON_MAX_NAME_SIZE = 10
  28. PLAYER_MAX_NAME_SIZE = 10
  29. MAXIMUM_LEVEL = 100
  30. IV_STAT_LIMIT = 31
  31. EV_LIMIT = 510
  32. EV_STAT_LIMIT = 252
  33. # Moves that permanently copy other moves
  34. SKETCH_MOVE_IDS = ["SKETCH"]
  35.  
  36. EBDX_INSTALLED = False
  37.  
  38. class Server:
  39.     def __init__(self, host, port, pbs_dir, rules_dir):
  40.         self.valid_party = make_party_validator(pbs_dir)
  41.         self.loop_count = 1
  42.         _,self.rules_files = find_changed_files(rules_dir,{})
  43.         self.rules = load_rules_files(rules_dir,self.rules_files)
  44.         self.host = host
  45.         self.port = port
  46.         self.rules_dir = rules_dir
  47.         self.socket = None
  48.         self.clients = {}
  49.         self.handlers = {
  50.             Connecting: self.handle_login_request,
  51.             LoggedIn: self.handle_loggedin,
  52.         }
  53.         self.socket_map = {}
  54.  
  55.     def run(self):
  56.         with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as self.socket:
  57.             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  58.             self.socket.bind((self.host, self.port))
  59.             logging.info('Started Server on %s:%d', self.host, self.port)
  60.             self.socket.listen()
  61.             while True:
  62.                 try:
  63.                     self.loop()
  64.                 except KeyboardInterrupt:
  65.                     logging.info('Stopping Server')
  66.                     break
  67.  
  68.     def broadcast_to_map(self, message, map_id, exclude_socket=None):
  69.         for s, st in self.clients.items():
  70.             if s is not exclude_socket and isinstance(st.state, LoggedIn) and st.state.map_id == map_id:
  71.                 #st.send_buffer += message + b"\n"
  72.                 st.send_buffer += message.encode('utf-8') + b"\n"
  73.     def loop(self):
  74.         if (self.loop_count % RULES_REFRESH_RATE) == 0:
  75.             reload_rules,rule_files = find_changed_files(self.rules_dir,self.rules_files)
  76.             if reload_rules:
  77.                 self.rules_files = rule_files
  78.                 self.rules = load_rules_files(self.rules_dir,self.rules_files)
  79.             self.loop_count = 0
  80.         self.loop_count += 1
  81.         reads = list(self.clients)
  82.         reads.append(self.socket)
  83.         writes = [s for s, st in self.clients.items() if st.send_buffer]
  84.         readable, writeable, errors = select.select(reads, writes, reads, 1.0)
  85.         for s in errors:
  86.             if s is self.socket:
  87.                 raise Exception("error on listening socket")
  88.             else:
  89.                 self.disconnect(s)
  90.  
  91.         for s in writeable:
  92.             st = self.clients.get(s)
  93.             if not st: continue
  94.             try:
  95.                 n = s.send(st.send_buffer)
  96.             except Exception as e:
  97.                 self.disconnect(s, e)
  98.             else:
  99.                 st.send_buffer = st.send_buffer[n:]
  100.  
  101.         for s in readable:
  102.             if s is self.socket:
  103.                 s, address = self.socket.accept()
  104.                 s.setblocking(False)
  105.                 st = self.clients[s] = State(address)
  106.                 client_id = s.fileno()
  107.                 self.socket_map[client_id] = s
  108.                 logging.info('%s: connect (assigned id %d)', st, client_id)
  109.             else:
  110.                 st = self.clients.get(s)
  111.                 if not st: continue
  112.                 try:
  113.                     recvd = s.recv(4096)
  114.                 except ConnectionResetError as e:
  115.                     self.disconnect(s)
  116.                 else:
  117.                     if recvd:
  118.                         recv_buffer = st.recv_buffer + recvd
  119.                         while True:
  120.                             message, _, recv_buffer = recv_buffer.partition(b"\n")
  121.                             if not _:
  122.                                 st.recv_buffer = message
  123.                                 break
  124.                             else:
  125.                                 try:
  126.                                     self.handlers[type(st.state)](s, st, message)
  127.                                 except Exception as e:
  128.                                     logging.exception('Server Error', exc_info=e)
  129.                                     self.disconnect(s, "server error")
  130.                     else:
  131.                         self.disconnect(s, "client disconnected")
  132.  
  133.     def disconnect(self, s, reason="unknown error"):
  134.         client_id = s.fileno()
  135.         if client_id in self.socket_map:
  136.             del self.socket_map[client_id]
  137.  
  138.         st = self.clients.pop(s, None)
  139.         if st:
  140.             if isinstance(st.state, LoggedIn) and st.state.map_id != -1:
  141.                 writer = RecordWriter()
  142.                 writer.str("player_left")
  143.                 writer.int(client_id)
  144.                 self.broadcast_to_map(writer.line(), st.state.map_id, exclude_socket=s)
  145.            
  146.             try:
  147.                 writer = RecordWriter()
  148.                 writer.str("disconnect")
  149.                 writer.str(reason)
  150.                 writer.send_now(s)
  151.                 s.close()
  152.             except Exception:
  153.                 pass
  154.             logging.info('%s: disconnected (%s)', st, reason)
  155.  
  156.     def handle_login_request(self, s, st, message):
  157.         client_id = s.fileno()
  158.         record = RecordParser(message.decode("utf8"))
  159.         if record.str() != "login":
  160.             self.disconnect(s, "bad assert: expected login")
  161.             return
  162.        
  163.         version = record.str()
  164.         # MODIFICADO: Usando Version de 'packaging' para la comparación
  165.         if not Version(version) >= GAME_VERSION:
  166.             self.disconnect(s, "invalid version")
  167.             return
  168.  
  169.         name = record.str()
  170.         id_ = record.int()
  171.         ttype = record.str()
  172.        
  173.         logging.debug('%s: Login attempt from %s (public_id: %d)', st, name, public_id(id_))
  174.        
  175.         if not self.valid_party(record):
  176.             self.disconnect(s, "invalid party")
  177.             return
  178.        
  179.         party_data = record.raw_all()
  180.         map_id, x, y, direction = -1, -1, -1, -1
  181.  
  182.         st.state = LoggedIn(name, id_, ttype, party_data, map_id, x, y, direction)
  183.        
  184.         writer = RecordWriter()
  185.         writer.str("login_ok")
  186.         writer.int(client_id)
  187.         writer.send(st)
  188.        
  189.         logging.info('%s: %s logged in successfully', st, name)
  190.    
  191.     def handle_loggedin(self, s, st, message):
  192.         client_id = s.fileno()
  193.         record = RecordParser(message.decode("utf8"))
  194.         msg_type = record.str()
  195.        
  196.         if msg_type == "move":
  197.             map_id = record.int()
  198.             x = record.int()
  199.             y = record.int()
  200.             direction = record.int()
  201.            
  202.             first_move = st.state.map_id == -1
  203.            
  204.             # MODIFICADO: Usar el método _replace para actualizar el estado inmutable.
  205.             # Esto es compatible con versiones de Python anteriores a 3.8.
  206.             st.state = st.state._replace(
  207.                 map_id=map_id,
  208.                 x=x,
  209.                 y=y,
  210.                 direction=direction
  211.             )
  212.            
  213.             if first_move:
  214.                 for other_s, other_st in self.clients.items():
  215.                     if s is not other_s and isinstance(other_st.state, LoggedIn) and other_st.state.map_id == map_id:
  216.                         writer = RecordWriter()
  217.                         writer.str("player_joined")
  218.                         writer.int(other_s.fileno())
  219.                         writer.int(other_st.state.map_id)
  220.                         writer.str(other_st.state.name)
  221.                         writer.str(other_st.state.trainertype)
  222.                         writer.int(other_st.state.x)
  223.                         writer.int(other_st.state.y)
  224.                         writer.int(other_st.state.direction)
  225.                         writer.raw(other_st.state.party)
  226.                         writer.send(st)
  227.  
  228.             writer = RecordWriter()
  229.             if first_move:
  230.                 writer.str("player_joined")
  231.                 writer.int(client_id)
  232.                 writer.int(map_id)
  233.                 writer.str(st.state.name)
  234.                 writer.str(st.state.trainertype)
  235.                 writer.int(x)
  236.                 writer.int(y)
  237.                 writer.int(direction)
  238.                 writer.raw(st.state.party)
  239.             else:
  240.                 writer.str("player_moved")
  241.                 writer.int(client_id)
  242.                 writer.int(map_id)
  243.                 writer.int(x)
  244.                 writer.int(y)
  245.                 writer.int(direction)
  246.            
  247.             self.broadcast_to_map(writer.line(), map_id, exclude_socket=s)
  248.  
  249.         elif msg_type == "request_interaction":
  250.             target_id = record.int()
  251.             target_socket = self.socket_map.get(target_id)
  252.             if target_socket:
  253.                 writer = RecordWriter()
  254.                 writer.str("interaction_request")
  255.                 writer.int(client_id)
  256.                 writer.str(st.state.name)
  257.                 target_st = self.clients.get(target_socket)
  258.                 if target_st:
  259.                     writer.send(target_st)
  260.  
  261.         elif msg_type == "accept_interaction":
  262.             target_id = record.int()
  263.             target_socket = self.socket_map.get(target_id)
  264.             if target_socket:
  265.                 writer = RecordWriter()
  266.                 writer.str("interaction_accepted")
  267.                 writer.int(client_id)
  268.                 # AÑADE el nombre aquí:
  269.                 writer.str(st.state.name)
  270.                 target_st = self.clients.get(target_socket)
  271.                 if target_st:
  272.                     writer.send(target_st)
  273.  
  274.     def write_server_rules(self,writer):
  275.         writer.int(len(self.rules))
  276.         for r in self.rules:
  277.             writer.raw(r)
  278.  
  279. class State:
  280.     def __init__(self, address):
  281.         self.address = address
  282.         self.state = Connecting()
  283.         self.send_buffer = b""
  284.         self.recv_buffer = b""
  285.  
  286.     def __str__(self):
  287.         state_name = type(self.state).__name__.lower()
  288.         if isinstance(self.state, LoggedIn):
  289.             return f"{self.address[0]}:{self.address[1]}/{state_name} ({self.state.name})"
  290.         return f"{self.address[0]}:{self.address[1]}/{state_name}"
  291.  
  292. Connecting = collections.namedtuple('Connecting', '')
  293.  
  294. # MODIFICADO: Eliminado el argumento 'mutable=True' para compatibilidad con Python < 3.8
  295. LoggedIn = collections.namedtuple('LoggedIn', 'name id trainertype party map_id x y direction')
  296.  
  297.  
  298. class RecordParser:
  299.     def __init__(self, line):
  300.         self.fields = []
  301.         field = ""
  302.         escape = False
  303.         for c in line:
  304.             if c == "," and not escape:
  305.                 self.fields.append(field)
  306.                 field = ""
  307.             elif c == "\\" and not escape:
  308.                 escape = True
  309.             else:
  310.                 field += c
  311.                 escape = False
  312.         self.fields.append(field)
  313.         self.fields.reverse()
  314.  
  315.     def bool(self):
  316.         return {'true': True, 'false': False}[self.fields.pop()]
  317.     def bool_or_none(self):
  318.         return {'true': True, 'false': False, '': None}[self.fields.pop()]
  319.     def int(self):
  320.         return int(self.fields.pop())
  321.     def int_or_none(self):
  322.         field = self.fields.pop()
  323.         if not field: return None
  324.         else: return int(field)
  325.     def str(self):
  326.         return self.fields.pop()
  327.     def raw_all(self):
  328.         data = list(reversed(self.fields))
  329.         self.fields = []
  330.         return data
  331.  
  332. def public_id(id_):
  333.     return id_ & 0xFFFF
  334.  
  335. class RecordWriter:
  336.     def __init__(self):
  337.         self.fields = []
  338.     def line(self):
  339.         return ",".join(RecordWriter.escape(str(f)) for f in self.fields)
  340.     def send_now(self, s):
  341.         line = self.line() + "\n"
  342.         s.sendall(line.encode("utf8"))
  343.     def send(self, st):
  344.         line = self.line() + "\n"
  345.         st.send_buffer += line.encode("utf8")
  346.     @staticmethod
  347.     def escape(f):
  348.         return f.replace("\\", "\\\\").replace(",", "\\,")
  349.     def int(self, i):
  350.         self.fields.append(str(i))
  351.     def str(self, s):
  352.         self.fields.append(s)
  353.     def raw(self, fs):
  354.         self.fields.extend(fs)
  355.        
  356. Pokemon = collections.namedtuple('Pokemon', 'genders abilities moves forms')
  357.  
  358. class Universe:
  359.     def __contains__(self, item):
  360.         return True
  361.  
  362. def make_party_validator(pbs_dir):
  363.     # ... (Esta función no necesita cambios)
  364.     ability_syms = set()
  365.     move_syms = set()
  366.     item_syms = set()
  367.     pokemon_by_name = {}
  368.  
  369.     with io.open(os.path.join(pbs_dir, r'abilities.txt'), 'r', encoding='utf-8-sig') as abilities_pbs:
  370.         for row in csv.reader(abilities_pbs):
  371.             if len(row) >= 2:
  372.                 ability_syms.add(row[1])
  373.  
  374.     with io.open(os.path.join(pbs_dir, r'moves.txt'), 'r', encoding='utf-8-sig') as moves_pbs:
  375.         for row in csv.reader(moves_pbs):
  376.             if len(row) >= 2:
  377.                 move_syms.add(row[1])
  378.  
  379.     with io.open(os.path.join(pbs_dir, r'items.txt'), 'r', encoding='utf-8-sig') as items_pbs:
  380.         for row in csv.reader(items_pbs):
  381.             if len(row) >= 2:
  382.                 item_syms.add(row[1])
  383.  
  384.     with io.open(os.path.join(pbs_dir, r'pokemon_server.txt'), 'r', encoding='utf-8-sig') as pokemon_pbs:
  385.         pokemon_pbs_ = configparser.ConfigParser()
  386.         pokemon_pbs_.read_file(pokemon_pbs)
  387.         for section in pokemon_pbs_.sections():
  388.             species = pokemon_pbs_[section]
  389.             if 'forms' in species:
  390.                 forms = {int(f) for f in species['forms'].split(',') if f}
  391.             else:
  392.                 forms = Universe()
  393.             genders = {
  394.                 'AlwaysMale': {0},
  395.                 'AlwaysFemale': {1},
  396.                 'Genderless': {2},
  397.             }.get(species['gender_ratio'], {0, 1})
  398.             ability_names = species['abilities'].split(',')
  399.             abilities = {a for a in ability_names if a}
  400.             moves = {m for m in species['moves'].split(',') if m}
  401.             pokemon_by_name[section] = Pokemon(genders, abilities, moves, forms)
  402.  
  403.     def validate_party(record):
  404.         logging.debug('--BEGIN PARTY VALIDATION--')
  405.         errors = []
  406.         try:
  407.             for _ in range(record.int()):
  408.                 def validate_pokemon():
  409.                     species = record.str()
  410.                     species_ = pokemon_by_name.get(species)
  411.                     if species_ is None:
  412.                         logging.debug('invalid species: %s', species)
  413.                         errors.append("invalid species")
  414.                     logging.debug('Species: %s', species)
  415.                     level = record.int()
  416.                     if not (1 <= level <= MAXIMUM_LEVEL):
  417.                         logging.debug('invalid level: %d', level)
  418.                         errors.append("invalid level")
  419.                     personal_id = record.int()
  420.                     owner_id = record.int()
  421.                     if owner_id & ~0xFFFFFFFF:
  422.                         logging.debug('invalid owner id: %d', owner_id)
  423.                         errors.append("invalid owner id")
  424.                     owner_name = record.str()
  425.                     if not (len(owner_name) <= PLAYER_MAX_NAME_SIZE):
  426.                         logging.debug('invalid owner name: %s', owner_name)
  427.                         errors.append("invalid owner name")
  428.                     owner_gender = record.int()
  429.                     if owner_gender not in {0, 1}:
  430.                         logging.debug('invalid owner gender: %d', owner_gender)
  431.                         errors.append("invalid owner gender")
  432.                     exp = record.int()
  433.                     form = record.int()
  434.                     if form not in species_.forms:
  435.                         logging.debug('invalid form: %d', form)
  436.                         errors.append("invalid form")
  437.                     item = record.str()
  438.                     if item and item not in item_syms:
  439.                         logging.debug('invalid item id: %s', item)
  440.                         errors.append("invalid item")
  441.                     can_use_sketch = not set(SKETCH_MOVE_IDS).isdisjoint(species_.moves)
  442.                     for _ in range(record.int()):
  443.                         move = record.str()
  444.                         if move:
  445.                             if can_use_sketch and move not in move_syms:
  446.                                 logging.debug('invalid move id (Sketched): %s', move)
  447.                             elif move not in species_.moves and not can_use_sketch:
  448.                                 logging.debug('invalid move id: %s', move)
  449.                                 errors.append("invalid move")
  450.                         ppup = record.int()
  451.                         if not (0 <= ppup <= 3):
  452.                             logging.debug('invalid ppup for move id %s: %d', move, ppup)
  453.                             errors.append("invalid ppup")
  454.                     for _ in range(record.int()):
  455.                         move = record.str()
  456.                         if move:
  457.                             if can_use_sketch and move not in move_syms:
  458.                                 logging.debug('invalid first move id (Sketched): %s', move)
  459.                             elif move not in species_.moves and not can_use_sketch:
  460.                                 logging.debug('invalid first move id: %s', move)
  461.                                 errors.append("invalid first move")
  462.                     gender = record.int()
  463.                     if gender not in species_.genders:
  464.                         logging.debug('invalid gender: %d', gender)
  465.                         errors.append("invalid gender")
  466.                     shiny = record.bool_or_none()
  467.                     ability = record.str()
  468.                     if ability and ability not in ability_syms:
  469.                         logging.debug('invalid ability: %s', ability)
  470.                         errors.append("invalid ability")
  471.                     ability_index = record.int_or_none()
  472.                     nature_id = record.str()
  473.                     nature_stats_id = record.str()
  474.                     ev_sum = 0
  475.                     for _ in range(6):
  476.                         iv = record.int()
  477.                         if not (0 <= iv <= IV_STAT_LIMIT):
  478.                             logging.debug('invalid IV: %d', iv)
  479.                             errors.append("invalid IV")
  480.                         ivmaxed = record.bool_or_none()
  481.                         ev = record.int()
  482.                         if not (0 <= ev <= EV_STAT_LIMIT):
  483.                             logging.debug('invalid EV: %d', ev)
  484.                             errors.append("invalid EV")
  485.                         ev_sum += ev
  486.                     if not (0 <= ev_sum <= EV_LIMIT):
  487.                        logging.debug('invalid EV sum: %d', ev_sum)
  488.                        errors.append("invalid EV sum")
  489.                     happiness = record.int()
  490.                     if not (0 <= happiness <= 255):
  491.                         logging.debug('invalid happiness: %d', happiness)
  492.                         errors.append("invalid happiness")
  493.                     name = record.str()
  494.                     if not (len(name) <= POKEMON_MAX_NAME_SIZE):
  495.                         logging.debug('invalid name: %s', name)
  496.                         errors.append("invalid name")
  497.                     poke_ball = record.str()
  498.                     if poke_ball and poke_ball not in item_syms:
  499.                         logging.debug('invalid pokeball: %s', poke_ball)
  500.                         errors.append("invalid pokeball")
  501.                     steps_to_hatch = record.int()
  502.                     pokerus = record.int()
  503.                     obtain_mode = record.int()
  504.                     obtain_map = record.int()
  505.                     obtain_text = record.str()
  506.                     obtain_level = record.int()
  507.                     hatched_map = record.int()
  508.                     cool = record.int()
  509.                     beauty = record.int()
  510.                     cute = record.int()
  511.                     smart = record.int()
  512.                     tough = record.int()
  513.                     sheen = record.int()
  514.                     for _ in range(record.int()):
  515.                         ribbon = record.str()
  516.                     if record.bool():
  517.                         m_item = record.str()
  518.                         m_msg = record.str()
  519.                         m_sender = record.str()
  520.                         m_species1 = record.int_or_none()
  521.                         if m_species1:
  522.                             m_gender1 = record.int()
  523.                             m_shiny1 = record.bool()
  524.                             m_form1 = record.int()
  525.                             m_shadow1 = record.bool()
  526.                             m_egg1 = record.bool()
  527.                        
  528.                         m_species2 = record.int_or_none()
  529.                         if m_species2:
  530.                             m_gender2 = record.int()
  531.                             m_shiny2 = record.bool()
  532.                             m_form2 = record.int()
  533.                             m_shadow2 = record.bool()
  534.                             m_egg2 = record.bool()
  535.                        
  536.                         m_species3 = record.int_or_none()
  537.                         if m_species3:
  538.                             m_gender3 = record.int()
  539.                             m_shiny3 = record.bool()
  540.                             m_form3 = record.int()
  541.                             m_shadow3 = record.bool()
  542.                             m_egg3 = record.bool()
  543.                     if record.bool():
  544.                         logging.debug('Fused Mon')
  545.                         validate_pokemon()
  546.                     if EBDX_INSTALLED:
  547.                         superhue = record.str()
  548.                         if shiny and (superhue == ""):
  549.                             logging.debug('uninitialized supershiny')
  550.                             errors.append("uninitialized supershiny")
  551.                         supervarient = record.bool_or_none()
  552.                     logging.debug('-------')
  553.                 validate_pokemon()
  554.             rest = record.raw_all()
  555.             if rest:
  556.                 errors.append(f"remaining data: {', '.join(rest)}")
  557.         except Exception as e:
  558.             errors.append(str(e))
  559.         if errors: logging.debug('Errors: %s', errors)
  560.         logging.debug('--END PARTY VALIDATION--')
  561.         return not errors
  562.        
  563.     return validate_party
  564.  
  565. def find_changed_files(directory,old_files_hash):
  566.     if os.path.isdir(directory):
  567.         new_files_hash = dict ([(f, os.stat(os.path.join(directory,f)).st_mtime) for f in os.listdir(directory)])
  568.         changed = old_files_hash.keys() != new_files_hash.keys()
  569.         if not changed:
  570.             for k in (old_files_hash.keys() & new_files_hash.keys()):
  571.                 if old_files_hash[k] != new_files_hash[k]:
  572.                     changed = True
  573.                     break
  574.         if changed:
  575.             logging.info('Refreshing Rules due to changes')
  576.             return True,new_files_hash
  577.     return False,old_files_hash
  578.    
  579. def load_rules_files(directory,files_hash):
  580.     rules = []
  581.     for f in iter(files_hash):
  582.         rule = []
  583.         with open(os.path.join(directory,f)) as rule_file:
  584.             for num,line in enumerate(rule_file):
  585.                 line = line.strip()
  586.                 if num == 3:
  587.                     rule.extend(line.split(','))
  588.                 else:
  589.                     rule.append(line)
  590.         rules.append(rule)
  591.     return rules
  592.  
  593. if __name__ == "__main__":
  594.     parser = argparse.ArgumentParser()
  595.     parser.add_argument("--host", default=HOST,help='The host IP Address to run this server on. Should be 0.0.0.0 for Google Cloud.')
  596.     parser.add_argument("--port", default=PORT,help='The port the server is listening on.')
  597.     parser.add_argument("--pbs_dir", default=PBS_DIR,help='The path, relative to the working directory, where the PBS files are located.')
  598.     parser.add_argument("--rules_dir", default=RULES_DIR,help='The path, relative to the working directory, where the rules files are located.')
  599.     parser.add_argument("--log", default="INFO",help='The log level of the server. Logging messages lower than the level are not written.')
  600.     args = parser.parse_args()
  601.     loglevel = getattr(logging, args.log.upper())
  602.     if not isinstance(loglevel, int):
  603.         raise ValueError('Invalid log level: %s' % loglevel)
  604.     logging.basicConfig(format='%(asctime)s: %(levelname)s: %(message)s', filename=os.path.join(LOG_DIR,'server.log'), level=loglevel)
  605.     logging.info('---------------')
  606.     Server(args.host, int(args.port), args.pbs_dir,args.rules_dir).run()
  607.     logging.shutdown()
Advertisement
Add Comment
Please, Sign In to add comment