Compare commits

..

1 commit

Author SHA1 Message Date
7ceee609b2 adds python implementations
- more README
- fix some C++ code along the way
2022-08-31 00:24:52 +02:00
3 changed files with 13 additions and 156 deletions

View file

@ -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*. Nowadays, you may have eared of their latest avatar: *web services*.
As our programmer is going to realize, one now have *two* problems. 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. 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 Because they are made to handle a **tremendous** number of complex situations,
most of which involve adversary users, users being bots, or both. 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. But most of the time, the actual problem does not really involve these situations.
At least not at the beginning (… which means probably never). At least not at the beginning (which means probably never).
People familiar with middleware history would argue that their key feature If you are building up (firsts versions of) communicating programs
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
that will run on a (safe) local network, 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: then I have good news:
**you don't have to use web services** (or any kind of middleware). **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 ### Overview
@ -55,7 +49,7 @@ in which you read/write.
Once you made your service on top of named pipes, Once you made your service on top of named pipes,
it is easy to wrap it within an interface made with other languages/tools. 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 Be warned that this is not secure, though, you should only use this for testing
purpose in a secured local network. purpose in a secured local network.
@ -73,13 +67,13 @@ The theoretical principle can be represented by this UML sequence diagram:
│ │ │ │ │ │ │ │
│ │ │┌──────╢ │ │ │┌──────╢
│ │ block││ wait ║ │ │ block││ wait ║
│ask │ │└─────> │ask │ │└─────
├─────────────>│ │ ├─────────────│ │
╟─────┐│ ├──────> ╟─────┐│ ├──────
║wait ││block │ ║process ║wait ││block │ ║process
<────┘│ │ ║ ────┘│ │ ║
│ │<──────────────┤ │ │──────────────┤
<─────┤ │ tell│ ─────┤ │ tell│
│ │ │ │ │ │ │ │
``` ```
@ -90,29 +84,6 @@ Notes:
for the sake of simplicity, but you may just as well use only one. 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 Build and run
------------- -------------

View file

@ -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)

View file

@ -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)