Foobar WTF
This commit is contained in:
parent
1f542b1720
commit
63c10720c6
49
foobar/kiss.py
Normal file
49
foobar/kiss.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import queue
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Hello There")
|
||||||
|
|
||||||
|
que = queue.Queue()
|
||||||
|
event = threading.Event()
|
||||||
|
|
||||||
|
#input(que)
|
||||||
|
input_thread = threading.Thread(target=input, args=(que,event))
|
||||||
|
input_thread.daemon = True
|
||||||
|
input_thread.start()
|
||||||
|
|
||||||
|
#output(que)
|
||||||
|
output_thread = threading.Thread(target=output, args=(que,event))
|
||||||
|
output_thread.daemon = True
|
||||||
|
output_thread.start()
|
||||||
|
|
||||||
|
for num in range(21):
|
||||||
|
print(f"wait till full: {num}/20", end='\r')
|
||||||
|
time.sleep(0.5)
|
||||||
|
print("\nDone!")
|
||||||
|
event.set()
|
||||||
|
|
||||||
|
def input(que, event):
|
||||||
|
loop = 0
|
||||||
|
while not event:
|
||||||
|
message = f"{time.time()} | Hi! {loop}"
|
||||||
|
que.put(message)
|
||||||
|
loop = loop + 1
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
def output(que, event):
|
||||||
|
file = '/tmp/test_out'
|
||||||
|
with open(file, 'a') as out_file:
|
||||||
|
while not event:
|
||||||
|
message = que.get()
|
||||||
|
out_file.write(f"{message}\r\n")
|
||||||
|
out_file.flush()
|
||||||
|
time.sleep(1)
|
||||||
|
out_file.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
print("Bye now!")
|
||||||
|
exit(0)
|
64
ircthing.py
64
ircthing.py
@ -1,28 +1,43 @@
|
|||||||
|
"""
|
||||||
|
My attempt to mimic Suckless.org's ii (irc it) software
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import multiprocessing
|
||||||
from ircthing_core import irc_router, connect_to_irc_server
|
from ircthing_core import irc_router, connect_to_irc_server
|
||||||
from ircthing_utils import read_config, cli_args, base_path
|
from ircthing_utils import read_config, cli_args, base_path
|
||||||
import time
|
|
||||||
import os
|
|
||||||
import multiprocessing
|
|
||||||
|
|
||||||
Processes = {}
|
Processes = {}
|
||||||
Stop_Toggle = multiprocessing.Event()
|
Stop_Toggle = multiprocessing.Event()
|
||||||
|
|
||||||
|
|
||||||
def clean_exit():
|
def clean_exit():
|
||||||
|
"""
|
||||||
|
Sets the Stop_Toggle event to signal clean exit.
|
||||||
|
"""
|
||||||
Stop_Toggle.set()
|
Stop_Toggle.set()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
"""
|
||||||
|
Main function to initialize irc connections specified on the configuration file.
|
||||||
|
|
||||||
|
This will run each irc server connection in invidual sub process.
|
||||||
|
Hold the process handlers on list.
|
||||||
|
Kill them with Stop_Toggle.
|
||||||
|
"""
|
||||||
root_path = base_path()
|
root_path = base_path()
|
||||||
|
|
||||||
# Get configuration file path if given
|
# Get configuration file path if given
|
||||||
config_path = 'config.ini'
|
config_path = "config.ini"
|
||||||
argument = cli_args()
|
argument = cli_args()
|
||||||
if argument:
|
if argument:
|
||||||
config_path = argument
|
config_path = argument
|
||||||
# Read configuration
|
# Read configuration
|
||||||
network_configs = read_config(config_path)
|
network_configs = read_config(config_path)
|
||||||
|
|
||||||
## Get irc socket for each network in configuration
|
## Get irc socket for each network in configuration
|
||||||
## Start thread for each socket
|
## Start thread for each socket
|
||||||
for network in network_configs:
|
for network in network_configs:
|
||||||
net_name = network["net_name"]
|
net_name = network["net_name"]
|
||||||
server = network["server"]
|
server = network["server"]
|
||||||
@ -31,42 +46,21 @@ def main():
|
|||||||
password = network["password"]
|
password = network["password"]
|
||||||
|
|
||||||
print(f"{time.time()} | Found configs for {net_name} network.")
|
print(f"{time.time()} | Found configs for {net_name} network.")
|
||||||
irc_socket, fifo_files, network_dir = connect_to_irc_server(root_path, net_name, server, port, nickname, password)
|
irc_socket, fifo_files, network_dir = connect_to_irc_server(
|
||||||
|
root_path, net_name, server, port, nickname, password
|
||||||
|
)
|
||||||
|
|
||||||
router_instance = irc_router(fifo_files, irc_socket, server, nickname, network_dir)
|
router_instance = irc_router(
|
||||||
|
fifo_files, irc_socket, server, nickname, network_dir
|
||||||
|
)
|
||||||
Processes[net_name] = multiprocessing.Process(target=router_instance.start)
|
Processes[net_name] = multiprocessing.Process(target=router_instance.start)
|
||||||
Processes[net_name].daemon = True
|
Processes[net_name].daemon = True
|
||||||
Processes[net_name].start()
|
Processes[net_name].start()
|
||||||
|
|
||||||
main_handle(root_path)
|
# Wait for all the sub processes to end.
|
||||||
|
|
||||||
for process in Processes.values():
|
for process in Processes.values():
|
||||||
process.join()
|
process.join()
|
||||||
|
|
||||||
def main_handle(path):
|
|
||||||
input = f"{path}/in"
|
|
||||||
output = f"{path}/out"
|
|
||||||
os.mkfifo(input)
|
|
||||||
os.mkfifo(output)
|
|
||||||
while True:
|
|
||||||
line = read_input(input)
|
|
||||||
write_output(output, line)
|
|
||||||
|
|
||||||
def read_input(file):
|
|
||||||
with open(file, 'r') as input:
|
|
||||||
line = input.readline().strip()
|
|
||||||
if not line:
|
|
||||||
return
|
|
||||||
if line == "exit":
|
|
||||||
clean_exit()
|
|
||||||
return line
|
|
||||||
|
|
||||||
def write_output(file, line):
|
|
||||||
with open(file, 'a') as output:
|
|
||||||
output.write(f"{time.time()} | {line}\r\n")
|
|
||||||
output.flush()
|
|
||||||
output.close()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print(f"{time.time()} | Lets start!")
|
print(f"{time.time()} | Lets start!")
|
||||||
@ -77,4 +71,4 @@ if __name__ == "__main__":
|
|||||||
finally:
|
finally:
|
||||||
clean_exit()
|
clean_exit()
|
||||||
print(f"{time.time()} | Bye!")
|
print(f"{time.time()} | Bye!")
|
||||||
exit(0)
|
sys.exit(0)
|
||||||
|
148
ircthing_core.py
148
ircthing_core.py
@ -1,9 +1,10 @@
|
|||||||
import time
|
import time
|
||||||
import re
|
import re
|
||||||
import asyncio
|
|
||||||
import socket
|
import socket
|
||||||
import os
|
import os
|
||||||
from ircthing_utils import make_files
|
from ircthing_utils import make_files
|
||||||
|
from threading import Thread, Event
|
||||||
|
|
||||||
|
|
||||||
def connect_to_irc_server(
|
def connect_to_irc_server(
|
||||||
base_path,
|
base_path,
|
||||||
@ -35,6 +36,7 @@ def connect_to_irc_server(
|
|||||||
|
|
||||||
|
|
||||||
class irc_router:
|
class irc_router:
|
||||||
|
|
||||||
def __init__(self, fifo_files, irc_socket, server, nickname, network_dir):
|
def __init__(self, fifo_files, irc_socket, server, nickname, network_dir):
|
||||||
self.fifo_files = fifo_files
|
self.fifo_files = fifo_files
|
||||||
self.irc_socket = irc_socket
|
self.irc_socket = irc_socket
|
||||||
@ -42,83 +44,98 @@ class irc_router:
|
|||||||
self.nickname = nickname
|
self.nickname = nickname
|
||||||
self.network_dir = network_dir
|
self.network_dir = network_dir
|
||||||
self.channels = []
|
self.channels = []
|
||||||
self._loop = asyncio.new_event_loop()
|
self.threads = []
|
||||||
|
self.disconnect_toggle = Event()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
try:
|
self.start_threads()
|
||||||
asyncio.set_event_loop(self._loop)
|
|
||||||
tasks = [self.user_listener(), self.irc_message_loop()]
|
|
||||||
self._loop.run_until_complete(asyncio.gather(*tasks))
|
|
||||||
finally:
|
|
||||||
for file in self.fifo_files:
|
|
||||||
try:
|
|
||||||
os.close(file)
|
|
||||||
except:
|
|
||||||
# Errors are okay at this point.
|
|
||||||
pass
|
|
||||||
self._loop.close()
|
|
||||||
|
|
||||||
## Main loop for reading irc inflow and routing to correct _out fifos.
|
for file in self.fifo_files:
|
||||||
## Also handle ping/pong here
|
try:
|
||||||
async def irc_message_loop(self):
|
os.close(file)
|
||||||
output_files=[]
|
except:
|
||||||
loop = asyncio.get_running_loop()
|
# Errors are okay at this point.
|
||||||
while True:
|
pass
|
||||||
|
self.irc_send("QUIT")
|
||||||
|
|
||||||
for output in self.fifo_files:
|
def start_threads(self):
|
||||||
if output.endswith('out'):
|
user_listener_thread = Thread(target=self.user_listener)
|
||||||
if output not in output_files:
|
irc_listener_thread = Thread(target=self.irc_message_loop)
|
||||||
print(f"{time.time()} | {self.server} has output file: {output}")
|
|
||||||
output_files.append(output)
|
self.threads.append(user_listener_thread)
|
||||||
|
self.threads.append(irc_listener_thread)
|
||||||
|
|
||||||
|
# start the threads
|
||||||
|
for thread in self.threads:
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
# wait for all the threads to reach end
|
||||||
|
for thread in self.threads:
|
||||||
|
thread.join()
|
||||||
|
|
||||||
|
def get_output_fifos(self):
|
||||||
|
output_fifos = []
|
||||||
|
for fifo in self.fifo_files:
|
||||||
|
if fifo.endswith("out") and fifo not in output_fifos:
|
||||||
|
output_fifos.append(fifo)
|
||||||
|
return output_fifos
|
||||||
|
|
||||||
|
def write_to_server_out(self, message):
|
||||||
|
server_out = os.path.join(self.network_dir, "out")
|
||||||
|
if os.access(server_out, os.W_OK):
|
||||||
|
self.write_to_out(server_out, message)
|
||||||
|
else:
|
||||||
|
print(f"{time.time()} | {self.server} | {message}")
|
||||||
|
|
||||||
|
def irc_message_loop(self):
|
||||||
|
while not self.disconnect_toggle.is_set():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
irc_input = await loop.sock_recv(self.irc_socket, 2048)
|
irc_input = self.irc_socket.recv(2048)
|
||||||
irc_input = irc_input.decode("utf-8")
|
irc_input = irc_input.decode("utf-8")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error reading from socket: {e}")
|
print(f"Error reading from socket: {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if irc_input:
|
if irc_input:
|
||||||
##
|
self.handle_irc_input(irc_input)
|
||||||
## The main logic hapens here.
|
time.sleep(0.5)
|
||||||
## support for channel joins
|
|
||||||
## and spliting the input to channel specifig channel/[in, out] locations
|
|
||||||
##
|
|
||||||
if "PING" in irc_input:
|
|
||||||
self.irc_send(f"PONG :{self.server}")
|
|
||||||
self.write_to_out(output_files[0], f"{time.time()} | ping/pong")
|
|
||||||
continue
|
|
||||||
|
|
||||||
if f":{self.server} 353" in irc_input:
|
def handle_irc_input(self, irc_input):
|
||||||
## We have joined a channel!
|
if "PING" in irc_input:
|
||||||
match = re.search(r'353 \S+ = (#\S+)', irc_input)
|
self.irc_send(f"PONG :{self.server}")
|
||||||
channel_join = match.group(1)
|
self.write_to_server_out("ping/pong")
|
||||||
await self.make_files(channel_join)
|
elif f":{self.server} 353" in irc_input:
|
||||||
continue
|
self.handle_channel_join(irc_input)
|
||||||
|
elif "PRIVMSG" in irc_input:
|
||||||
|
self.handle_privmsg(irc_input)
|
||||||
|
else:
|
||||||
|
self.write_to_server_out(irc_input)
|
||||||
|
|
||||||
if "PRIVMSG" in irc_input:
|
def handle_channel_join(self, irc_input):
|
||||||
if self.if_input_belongs_to_channel(irc_input):
|
## We have joined a channel!
|
||||||
continue
|
channel = re.search(r"353 \S+ = (#\S+)", irc_input).group(1)
|
||||||
|
self.make_files(channel)
|
||||||
|
|
||||||
self.write_to_out(output_files[0], irc_input)
|
def handle_privmsg(self, irc_input):
|
||||||
|
if not self.input_belongs_to_channel(irc_input):
|
||||||
|
self.write_to_server_out(irc_input)
|
||||||
|
|
||||||
await asyncio.sleep(0.1)
|
def input_belongs_to_channel(self, input):
|
||||||
|
output_files = self.get_output_fifos()
|
||||||
def if_input_belongs_to_channel(self, input):
|
|
||||||
# We know that input includes "PRIVMSG"
|
# We know that input includes "PRIVMSG"
|
||||||
# But to where it shoudl go?
|
# But to where it shoudl go?
|
||||||
message = re.search(r':.*:(.*)', input).group(1)
|
message = re.search(r":.*:(.*)", input).group(1)
|
||||||
input_user = re.search(r'^:(\S+)', input).group(1)
|
input_user = re.search(r"^:(\S+)", input).group(1)
|
||||||
input_channel = re.search(r'PRIVMSG (\S+) :', input)
|
input_channel = re.search(r"PRIVMSG (\S+) :", input).group(1)
|
||||||
done=False
|
done = False
|
||||||
for file in self.fifo_files:
|
for file in output_files:
|
||||||
if input_channel.group(1) in file:
|
if input_channel in file:
|
||||||
if file.endswith("out"):
|
self.write_to_out(file, f"{input_user}: {message}")
|
||||||
self.write_to_out(file, f"{input_user}: {message}")
|
done = True
|
||||||
done=True
|
|
||||||
return done
|
return done
|
||||||
|
|
||||||
async def make_files(self, channel):
|
def make_files(self, channel):
|
||||||
network_path = os.path.dirname(self.fifo_files[1])
|
network_path = os.path.dirname(self.fifo_files[1])
|
||||||
channel_dir = os.path.join(network_path, channel)
|
channel_dir = os.path.join(network_path, channel)
|
||||||
os.makedirs(channel_dir, exist_ok=True)
|
os.makedirs(channel_dir, exist_ok=True)
|
||||||
@ -134,7 +151,6 @@ class irc_router:
|
|||||||
fifo_files.append(f"{channel_dir}/in")
|
fifo_files.append(f"{channel_dir}/in")
|
||||||
fifo_files.append(f"{channel_dir}/out")
|
fifo_files.append(f"{channel_dir}/out")
|
||||||
self.fifo_files.extend(fifo_files)
|
self.fifo_files.extend(fifo_files)
|
||||||
await asyncio.sleep(1)
|
|
||||||
|
|
||||||
def write_to_out(self, file, input):
|
def write_to_out(self, file, input):
|
||||||
if file == None:
|
if file == None:
|
||||||
@ -149,29 +165,28 @@ class irc_router:
|
|||||||
self.irc_socket.send(bytes(f"{message}\r\n", "utf-8"))
|
self.irc_socket.send(bytes(f"{message}\r\n", "utf-8"))
|
||||||
print(f"{time.time()} | Send: {message}")
|
print(f"{time.time()} | Send: {message}")
|
||||||
|
|
||||||
async def async_readline(self, file, queue):
|
def async_readline(self, file, queue):
|
||||||
print(f"Trying to read from file {file}")
|
print(f"Trying to read from file {file}")
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
with open(file, mode='r') as in_file:
|
with open(file, mode="r") as in_file:
|
||||||
line = in_file.readline().strip()
|
line = in_file.readline().strip()
|
||||||
if not line:
|
if not line:
|
||||||
print("There was no line!")
|
print("There was no line!")
|
||||||
continue
|
continue
|
||||||
await queue.put(line)
|
queue.put(line)
|
||||||
in_file.close()
|
in_file.close()
|
||||||
await asyncio.sleep(0.5)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"ERROR IN async_readline func: {e}")
|
print(f"ERROR IN async_readline func: {e}")
|
||||||
|
|
||||||
async def process_user_input(self, queue):
|
def process_user_input(self, queue):
|
||||||
print("Processing of user input may start!")
|
print("Processing of user input may start!")
|
||||||
while True:
|
while True:
|
||||||
line = await queue.get()
|
line = await queue.get()
|
||||||
print(f"{time.time()} | trying to send: {line} to {self.server}")
|
print(f"{time.time()} | trying to send: {line} to {self.server}")
|
||||||
|
|
||||||
self.irc_send(line)
|
self.irc_send(line)
|
||||||
await asyncio.sleep(0.2)
|
time.sleep(0.5)
|
||||||
|
|
||||||
async def user_listener(self):
|
async def user_listener(self):
|
||||||
print("User Listener is HERE!")
|
print("User Listener is HERE!")
|
||||||
@ -189,5 +204,4 @@ class irc_router:
|
|||||||
# Wait for all tasks to complete
|
# Wait for all tasks to complete
|
||||||
await asyncio.gather(*tasks)
|
await asyncio.gather(*tasks)
|
||||||
finally:
|
finally:
|
||||||
self.irc_send('QUIT')
|
self.irc_send("QUIT")
|
||||||
|
|
||||||
|
@ -1,23 +1,53 @@
|
|||||||
|
"""
|
||||||
|
ircthing_utils
|
||||||
|
|
||||||
|
Some functions that make life nicer.
|
||||||
|
"""
|
||||||
|
|
||||||
import configparser
|
import configparser
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Union, List, Tuple
|
||||||
|
|
||||||
def base_path():
|
|
||||||
|
def base_path() -> str:
|
||||||
|
"""
|
||||||
|
Returns location that the script will use as root for its dir structure
|
||||||
|
Returns:
|
||||||
|
str: path for run time files
|
||||||
|
"""
|
||||||
my_name = sys.argv[0]
|
my_name = sys.argv[0]
|
||||||
my_name_pyless, _ = os.path.splitext(my_name)
|
my_name_pyless, _ = os.path.splitext(my_name)
|
||||||
return f'/tmp/{my_name_pyless}'
|
return f"/tmp/{my_name_pyless}"
|
||||||
|
|
||||||
def cli_args():
|
|
||||||
parser = argparse.ArgumentParser(description="Usage: python3.11 ircthing.py /myconfig.ini")
|
def cli_args() -> Union[str, None]:
|
||||||
parser.add_argument('config', help="Path to the configuration file.")
|
"""
|
||||||
|
Parse arguments and provide small usage message
|
||||||
|
Returns:
|
||||||
|
str or None: path to config file
|
||||||
|
"""
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Usage: python3.11 ircthing.py /myconfig.ini"
|
||||||
|
)
|
||||||
|
parser.add_argument("config", help="Path to the configuration file.")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
if args.config:
|
if args.config:
|
||||||
return args.config
|
return args.config
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def read_config(config_path):
|
|
||||||
|
def read_config(config_path: str) -> List[dict]:
|
||||||
|
"""
|
||||||
|
Read configuration file and return list of dicts.
|
||||||
|
Dictionaries hold information about irc networks/server to connecto to.
|
||||||
|
args:
|
||||||
|
str: Path to the configuration file.
|
||||||
|
Returns:
|
||||||
|
list[{}, {}]: List of dictionaries.
|
||||||
|
"""
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.read(config_path)
|
config.read(config_path)
|
||||||
|
|
||||||
@ -43,12 +73,21 @@ def read_config(config_path):
|
|||||||
}
|
}
|
||||||
network_configs.append(network_config)
|
network_configs.append(network_config)
|
||||||
return network_configs
|
return network_configs
|
||||||
except Exception as e:
|
except Exception as config_read_error:
|
||||||
print(f"Failure while reading configuration file. {e}")
|
print(f"Failure while reading configuration file. {config_read_error}")
|
||||||
exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def make_files(path, net_name):
|
|
||||||
|
|
||||||
|
def make_files(path: str, net_name: str) -> Tuple[List[str], str]:
|
||||||
|
"""
|
||||||
|
Make directories and fifo files need to make irc server connection.
|
||||||
|
Args:
|
||||||
|
str: The root path for run time files.
|
||||||
|
str: The network name of the irc server we are joining
|
||||||
|
Returns:
|
||||||
|
list: List containing the fio files created.
|
||||||
|
str: Path to the directory created for the network connection.
|
||||||
|
"""
|
||||||
os.makedirs(path, exist_ok=True)
|
os.makedirs(path, exist_ok=True)
|
||||||
server_dir = os.path.join(path, net_name)
|
server_dir = os.path.join(path, net_name)
|
||||||
os.makedirs(server_dir, exist_ok=True)
|
os.makedirs(server_dir, exist_ok=True)
|
||||||
@ -64,4 +103,3 @@ def make_files(path, net_name):
|
|||||||
fifo_files.append(f"{server_dir}/in")
|
fifo_files.append(f"{server_dir}/in")
|
||||||
fifo_files.append(f"{server_dir}/out")
|
fifo_files.append(f"{server_dir}/out")
|
||||||
return fifo_files, server_dir
|
return fifo_files, server_dir
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user