Compare commits
3 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c58b426876 | |||
| 4b42f79590 | |||
| 016852e281 |
3 changed files with 156 additions and 13 deletions
55
README.md
55
README.md
|
|
@ -21,18 +21,24 @@ 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 complex situations,
|
||||
most of which involve adversary users, users being bots, or both.
|
||||
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.
|
||||
|
||||
But most of the time, the actual problem does not really involve these situations.
|
||||
At least not at the beginning (which means probably never).
|
||||
If you are building up (firsts versions of) communicating programs
|
||||
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
|
||||
that will run on a (safe) local network,
|
||||
and for which the exchanged messages are known,
|
||||
and for which the exchanged messages are known and simple,
|
||||
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
|
||||
|
|
@ -49,7 +55,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`.
|
||||
For instance, it is very easy to expose it on the network using common tools like `socat` (see below).
|
||||
|
||||
Be warned that this is not secure, though, you should only use this for testing
|
||||
purpose in a secured local network.
|
||||
|
|
@ -67,13 +73,13 @@ The theoretical principle can be represented by this UML sequence diagram:
|
|||
│ │ │ │
|
||||
│ │ │┌──────╢
|
||||
│ │ block││ wait ║
|
||||
│ask │ │└─────→║
|
||||
├─────────────→│ │
|
||||
╟─────┐│ ├──────→│
|
||||
│ask │ │└─────>║
|
||||
├─────────────>│ │
|
||||
╟─────┐│ ├──────>│
|
||||
║wait ││block │ ║process
|
||||
║←────┘│ │ ║
|
||||
│ │←──────────────┤
|
||||
│←─────┤ │ tell│
|
||||
║<────┘│ │ ║
|
||||
│ │<──────────────┤
|
||||
│<─────┤ │ tell│
|
||||
│ │ │ │
|
||||
```
|
||||
|
||||
|
|
@ -84,6 +90,29 @@ 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
|
||||
-------------
|
||||
|
||||
|
|
|
|||
21
service1.py
Executable file
21
service1.py
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
#!/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)
|
||||
93
service2.py
Executable file
93
service2.py
Executable file
|
|
@ -0,0 +1,93 @@
|
|||
#!/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)
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue