diff --git a/README.md b/README.md index 6ce5a35..d9a82e4 100644 --- a/README.md +++ b/README.md @@ -21,24 +21,18 @@ If you don't really now what a middleware is, be at ease, nobody really knows. Nowadays, you may have eared of their latest avatar: *web services*. As our programmer is going to realize, one now have *two* problems. The burden of writing, using, and maintaining code using middleware is always huge. -Because they are made to handle a **tremendous** number of features and complex situations -—most of which involve adversary users, users being bots, or both. +Because they are made to handle a **tremendous** number of complex situations, +most of which involve adversary users, users being bots, or both. But most of the time, the actual problem does not really involve these situations. -At least not at the beginning (… which means probably never). -People familiar with middleware history would argue that their key feature -is not just *messages passing* but *remote call*, which involves *object serialization*. -But most of the time, the messages are pretty simple anyway, and using a middleware -to implement a serialization of a list of instances having three members of fundamental types -is not a good use of your time. - -If you are building up (firsts versions of) two communicating programs +At least not at the beginning (which means probably never). +If you are building up (firsts versions of) communicating programs that will run on a (safe) local network, -and for which the exchanged messages are known and simple, +and for which the exchanged messages are known, then I have good news: **you don't have to use web services** (or any kind of middleware). -**YOU JUST NEED TO KNOW HOW TO READ/WRITE FROM/TO (SPECIAL) FILES**. +**You just need to know how to read/write from/to (special) files**. ### Overview @@ -55,7 +49,7 @@ in which you read/write. Once you made your service on top of named pipes, it is easy to wrap it within an interface made with other languages/tools. -For instance, it is very easy to expose it on the network using common tools like `socat` (see below). +For instance, it is very easy to expose it on the network using common tools like `socat`. Be warned that this is not secure, though, you should only use this for testing purpose in a secured local network. @@ -73,13 +67,13 @@ The theoretical principle can be represented by this UML sequence diagram: │ │ │ │ │ │ │┌──────╢ │ │ block││ wait ║ - │ask │ │└─────>║ - ├─────────────>│ │ - ╟─────┐│ ├──────>│ + │ask │ │└─────→║ + ├─────────────→│ │ + ╟─────┐│ ├──────→│ ║wait ││block │ ║process - ║<────┘│ │ ║ - │ │<──────────────┤ - │<─────┤ │ tell│ + ║←────┘│ │ ║ + │ │←──────────────┤ + │←─────┤ │ tell│ │ │ │ │ ``` @@ -90,29 +84,6 @@ Notes: for the sake of simplicity, but you may just as well use only one. -### When NOT to use named pipes - -To be completely honest, here are a list of cases that —**if they are all true**— -may lead you to consider that maybe it would be a good idea -to think about how you may eventually end up -looking for a solution that might be something that's close to a middleware: - -- ☒ your service takes time to compute something, -- ☒ you have one service, but an unknown (large) number of clients, -- ☒ all clients expect the same interface, -- ☒ which involves answering to the server, -- ☒ with *complex* data structures, -- ☒ you absolutely need to serve them all as fast as possible, -- ☒ over the internet, -- ☒ and you are *certain* that no one will want *another* middleware in the next project. - -I your use case don't match all of this checklist but you still want to -use a middleware, maybe you should just consider making a side software -that will expose/transliterate the data going through the named pipe. -That way, your service stays simple and you can easily -exchange one middleware for another without even touching it. - - Build and run ------------- diff --git a/service1.py b/service1.py deleted file mode 100755 index c47ddad..0000000 --- a/service1.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python - -import sys - -if __name__ == "__main__": - print("Start server") - - while True: - with open(sys.argv[1]) as fin: - datas = fin.readline() - - data = datas.strip() - print("Received: <",data,">", file=sys.stderr) - - with open(sys.argv[2], 'w') as fout: - fout.write(data) - - if data == "exit": - break - - print("Stop server", file=sys.stderr) diff --git a/service2.py b/service2.py deleted file mode 100755 index 0fd851f..0000000 --- a/service2.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python - -from enum import Enum -import threading -import stat -import sys -import os - -class ERROR(Enum): - NOT_FIFO = 1 - -class Service: - def __init__(self, context: str, data: str, out: str) -> None: - self._has_current_context: bool = False - self._mutex = threading.Lock() - self._file_current_context: str = context - self._file_data: str = data - self._out: str = out - self._current_context: str = "" - - def get_has_current_context(self) -> bool: - return self._has_current_context - - def set_has_current_context(self, flag: bool) -> None: - self._mutex.acquire() - self._has_current_context = flag - self._mutex.release() - - def update_current_context(self) -> None: - while True: - print("Wait for context...", file = sys.stderr) - has_error: bool = False - try: - with open(self._file_current_context) as if_current_context: - self._current_context: str = if_current_context.readline().strip() - except: - has_error = True - - if not has_error: - self.set_has_current_context(True) - print("\tReceived context:", self._current_context, file=sys.stderr) - - def handle_data(self) -> None: - while True: - if self.get_has_current_context(): - print("Wait for data...", file=sys.stderr) - has_error: bool = False - try: - with open(self._file_data) as if_data: - data: str = if_data.readline().strip() - except: - has_error = True - - if not has_error: - print("\tReceived data:",data, file=sys.stderr) - - print("Do stuff...", file=sys.stderr) - result: str = self._current_context + ":" + data - print("\tdone", file=sys.stderr) - - print("Output...", file=sys.stderr) - with open(self._out, 'w') as out: - out.write(result) - - print("\tdone", file=sys.stderr) - -def is_named_pipe_fifo(filename: str): - st = os.stat(filename) - return stat.S_ISFIFO(st.st_mode) - -if __name__ == "__main__": - - assert(len(sys.argv) == 4) - - for i in range(1,4): - if not is_named_pipe_fifo(sys.argv[i]): - print("ERROR:", sys.argv[i], "is not a named pipe FIFO", file=sys.stderr) - sys.exit(ERROR.NO_FIFO) - - print("Start server", file=sys.stderr, flush=True) - server = Service(sys.argv[1], sys.argv[2], sys.argv[3]) - - do_current_context = threading.Thread( target = server.update_current_context ) - do_tasks = threading.Thread( target = server.handle_data ) - - do_current_context.start() - do_tasks.start() - - do_current_context.join() - do_tasks.join() - - print("End", file=sys.stderr) -