6 Commits

Author SHA1 Message Date
b61634fea9 2024-08-15 17:19:40 +02:00
6b6658f56d 2024-08-15 14:36:55 +02:00
d56f7a2249 2024-08-14 15:48:24 +02:00
2b45f5aa7e 2024-08-14 15:33:56 +02:00
a3fef1c38c 2024-08-14 13:50:09 +02:00
a64876cfa0 init 2024-08-14 13:18:04 +02:00
116 changed files with 2493 additions and 4445 deletions

View File

@ -24,10 +24,6 @@ body:
label: Ce problème est il relatif à un ou des modules en particulier ?
multiple: true
options:
- Interface utilisateur⋅ice (crates/app)
- Encapsulation Tauri (crates/desktop)
- Moteur SESAM-Vitale (crates/sesam-vitale)
- Librairie utilitaire (crates/utils)
- Documentation (docs)
- Scripts (scripts)
- Autre
- Clego
- Tauri
- Axum

2
.gitignore vendored
View File

@ -21,5 +21,3 @@ target/
*.sln
*.sw?
# Ignore .env files
.env

1100
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,7 @@
[workspace]
resolver = "2"
members = [
"crates/backend",
"crates/desktop",
"crates/app",
"crates/sesam-vitale",
"crates/fsv-sys",
"crates/utils",
"crates/desktop"
]

View File

@ -2,76 +2,67 @@
Logiciel de Pharmacie libre et open-source.
## Modules applicatifs
## Crates
- `crates`: Dossier racine des modules Rust
- `crates/backend`: Serveur backend propulsé par Axum, exposant une API REST
- `crates/desktop`: Client desktop propulsé par Tauri, exposant le `frontend`
- `crates/sesam-vitale`: Bibliothèque de gestion des services SESAM-Vitale (Lecture des cartes CPS et Vitale, téléservices ...)
- `crates/utils`: Bibliothèque de fonctions utilitaires
- `crates/fsv-sys`: Bindings Rust pour les librairies dynamiques FSV (SESAM-Vitale)
- `frontend`: Interface web du logiciel, propulsée par Nuxt.js
## Installation
### Fichiers de configuration
Certaines librairies nécessitent de définir certaines paramètres de configuration pour fonctionner correctement, en particulier le moteur SESAM-Vitale.
Ces paramètres sont définis dans un fichier de configuration `.env` situé dans un des dossiers suivant (par ordre de priorité) :
- dans le dossier courant (`./.env`)
- dans le dossier du manifeste (par exemple `crates/sesam-vitale/.env`)
- dans le dossier de configuration standard de l'OS (par exemple, sur linux, `~/.config/krys4lide/.env` - [plus d'info](https://github.com/dirs-dev/directories-rs?tab=readme-ov-file#projectdirs))
Des exemples de fichiers de configuration sont disponibles à la racine du projet : `.env.linux.example` et `.env.win.example`.
- `app`: Interface du logiciel, servie par un serveur web propulsé par Axum. Utilisable en mode endpoint ou encapsulé dans le client `desktop`
- `desktop`: Client desktop propulsé par Tauri, encapsulant le serveur web `app`
- `sesam-vitale`: Bibliothèque de gestion des services SESAM-Vitale (Lecture des cartes CPS et Vitale, téléservices ...)
## Development
### Pré-requis
#### Frontend (Nuxt + Typescript)
Le frontend est propulsé par Nuxt.js, un framework TypeScript pour Vue.js. Pour le développement, il est nécessaire d'installer les dépendances suivantes :
- [Bun](https://bun.sh/docs/installation), un gestionnaire de paquets, équivalent à `npm` en plus performant
#### Tauri CLI
TODO: Tauri CLI, réellement nécessaire ?
La CLI Tauri est nécessaire au lancement du client `desktop`. Elle peut être installée via Cargo :
```bash
cargo install tauri-cli --version "^2.0.0-rc"
cargo install tauri-cli --version "^2.0.0-beta"
```
#### FSV-sys
#### Tailwindcss CLI
La crate `fsv-sys` nécessite la présence des librairies fournies par le package FSV et la CryptolibCPS. Les instructions d'installation sont disponibles dans le [README](crates/sesam-vitale/README.md) de la crate `fsv-sys`.
Le CLI Tailwindcss est nécessaire pour la génération du fichier `crates/app/assets/css/style.css`.
#### Backend Hot-reload
La documentation d'installation est disponible sur le site officiel de Tailwindcss : https://tailwindcss.com/blog/standalone-cli
Voir le [README](crates/backend/README.md) de la crate `backend` pour les prérequis de développement du serveur backend.
La version actuellement utilisée est la [`v3.4.7`](https://github.com/tailwindlabs/tailwindcss/releases/tag/v3.4.7)
#### SESAM-Vitale
La crate `sesam-vitale` nécessite la présence des librairies dynamiques fournies par le package FSV et la CryptolibCPS. Les instructions d'installation sont disponibles dans le [README](crates/sesam-vitale/README.md) de la crate `sesam-vitale`.
### Lancement
Pour lancer l'application en mode développement, il est nécessaire d'exécuter plusieurs composants simultanément :
Le logiciel dans sa globalité peut être lancé via la commande suivante :
```bash
# Lancement du serveur backend
systemfd --no-pid -s http::3030 -- cargo watch -x 'run --bin backend'
```
```bash
# Lancement de l'interface utilisateur (frontend ou desktop)
# - frontend (serveur web, accessible via navigateur)
bun run --cwd frontend/ dev
# - desktop (client desktop, basé sur Tauri)
cargo tauri dev
```
/!\ Attention, le lancement du client `desktop` ne génère pas le fichier `crates/app/assets/css/style.css` automatiquement pour le moment. En cas de modification des interfaces web, il est donc nécessaire de procéder à sa génération comme indiqué dans le [README](crates/app/README.md) de la crate `app`.
Si vous souhaitez lancer les composants séparément, les indications de lancement sont disponibles dans les README des différents crates.
- [app](crates/app/README.md)
- [sesam-vitale](crates/sesam-vitale/README.md)
## Rechargement automatique
Pour permettre de développer plus rapidement, il existe une librairie qui recompile automatiquement nos modifications en cours : [`cargo-watch`](https://github.com/watchexec/cargo-watch) permet de relancer une commande `cargo` lorsqu'un fichier est modifié (example: `cargo run` --> `cargo watch -x run`).
Voici la commande pour l'installer dans un _package_ :
```bash
cargo add cargo-watch --dev --package app
```
Le fichier [`.ignore`](./ignore) permet d'ignorer certains fichiers pour éviter de relancer la recompilation inutilement.
⚠️ La librairie n'est pas compatible avec _Windows 7_ et les versions antérieurs de _Windows_.
## Build
Pour packager le client `desktop`, il est nécessaire de faire appel à la CLI Tauri, qui se charge de gérer le build du `frontend` et son intégration au bundle :
Packager le client desktop
```bash
cargo tauri build

View File

@ -7,11 +7,9 @@ edition = "2021"
askama = "0.12.1"
askama_axum = "0.4.0"
axum = "0.7.5"
axum-htmx = { version = "0.6", features = ["auto-vary"] }
listenfd = "1.0.1"
notify = "6.1.1"
serde = { version = "1.0.204", features = ["derive"] }
thiserror = "1.0.63"
tokio = { version = "1.39.1", features = ["macros", "rt-multi-thread"] }
tower-http = { version = "0.5.2", features = ["fs"] }
tower-livereload = "0.9.3"

View File

@ -1,6 +0,0 @@
[general]
# Directories to search for templates, relative to the crate root.
dirs = [
"src/pages",
"src/components",
]

File diff suppressed because one or more lines are too long

View File

@ -566,8 +566,28 @@ video {
border-width: 0;
}
.z-50 {
z-index: 50;
.absolute {
position: absolute;
}
.relative {
position: relative;
}
.-inset-0\.5 {
inset: -0.125rem;
}
.-inset-1\.5 {
inset: -0.375rem;
}
.right-0 {
right: 0px;
}
.z-10 {
z-index: 10;
}
.mx-auto {
@ -575,11 +595,38 @@ video {
margin-right: auto;
}
.my-4 {
margin-top: 1rem;
.-mr-2 {
margin-right: -0.5rem;
}
.ml-3 {
margin-left: 0.75rem;
}
.ml-auto {
margin-left: auto;
}
.mt-2 {
margin-top: 0.5rem;
}
.mt-3 {
margin-top: 0.75rem;
}
.mb-4 {
margin-bottom: 1rem;
}
.mt-4 {
margin-top: 1rem;
}
.mt-6 {
margin-top: 1.5rem;
}
.mb-2 {
margin-bottom: 0.5rem;
}
@ -588,22 +635,10 @@ video {
margin-bottom: 0.625rem;
}
.mb-4 {
margin-bottom: 1rem;
}
.me-3 {
margin-inline-end: 0.75rem;
}
.mt-3 {
margin-top: 0.75rem;
}
.mt-4 {
margin-top: 1rem;
}
.block {
display: block;
}
@ -628,44 +663,52 @@ video {
height: 2.5rem;
}
.h-2 {
height: 0.5rem;
.h-16 {
height: 4rem;
}
.h-2\.5 {
height: 0.625rem;
}
.h-32 {
height: 8rem;
}
.h-4 {
height: 1rem;
}
.h-48 {
height: 12rem;
}
.h-5 {
height: 1.25rem;
}
.h-7 {
height: 1.75rem;
.h-6 {
height: 1.5rem;
}
.h-8 {
height: 2rem;
}
.h-full {
height: 100%;
}
.h-32 {
height: 8rem;
}
.h-48 {
height: 12rem;
}
.h-96 {
height: 24rem;
}
.h-full {
height: 100%;
.h-2\.5 {
height: 0.625rem;
}
.h-9 {
height: 2.25rem;
}
.h-7 {
height: 1.75rem;
}
.h-2 {
height: 0.5rem;
}
.h-4 {
height: 1rem;
}
.min-h-full {
@ -676,38 +719,58 @@ video {
width: 2.5rem;
}
.w-32 {
width: 8rem;
}
.w-48 {
width: 12rem;
}
.w-5 {
width: 1.25rem;
.w-6 {
width: 1.5rem;
}
.w-8 {
width: 2rem;
}
.w-full {
width: 100%;
.w-auto {
width: auto;
}
.w-32 {
width: 8rem;
}
.w-20 {
width: 5rem;
}
.w-24 {
width: 6rem;
}
.w-28 {
width: 7rem;
}
.max-w-7xl {
max-width: 80rem;
}
.max-w-screen-xl {
max-width: 1280px;
.max-w-xs {
max-width: 20rem;
}
.max-w-sm {
max-width: 24rem;
}
.flex-shrink-0 {
flex-shrink: 0;
}
.origin-top-right {
transform-origin: top right;
}
@keyframes pulse {
50% {
opacity: .5;
@ -718,20 +781,12 @@ video {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
.list-none {
list-style-type: none;
}
.grid-cols-1 {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
.flex-col {
flex-direction: column;
}
.flex-wrap {
flex-wrap: wrap;
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.items-center {
@ -750,64 +805,46 @@ video {
gap: 1rem;
}
.space-x-3 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.75rem * var(--tw-space-x-reverse));
margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse)));
}
.divide-y > :not([hidden]) ~ :not([hidden]) {
--tw-divide-y-reverse: 0;
border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));
border-bottom-width: calc(1px * var(--tw-divide-y-reverse));
}
.divide-gray-100 > :not([hidden]) ~ :not([hidden]) {
--tw-divide-opacity: 1;
border-color: rgb(243 244 246 / var(--tw-divide-opacity));
}
.self-center {
align-self: center;
}
.truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.whitespace-nowrap {
white-space: nowrap;
}
.rounded {
border-radius: 0.25rem;
.space-y-1 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));
}
.rounded-full {
border-radius: 9999px;
}
.rounded-md {
border-radius: 0.375rem;
}
.rounded-lg {
border-radius: 0.5rem;
}
.border {
border-width: 1px;
.rounded {
border-radius: 0.25rem;
}
.border-2 {
border-width: 2px;
}
.border-dashed {
border-style: dashed;
.border {
border-width: 1px;
}
.border-gray-100 {
--tw-border-opacity: 1;
border-color: rgb(243 244 246 / var(--tw-border-opacity));
.border-b {
border-bottom-width: 1px;
}
.border-t {
border-top-width: 1px;
}
.border-dashed {
border-style: dashed;
}
.border-gray-200 {
@ -820,9 +857,9 @@ video {
border-color: rgb(209 213 219 / var(--tw-border-opacity));
}
.bg-blue-700 {
.bg-white {
--tw-bg-opacity: 1;
background-color: rgb(29 78 216 / var(--tw-bg-opacity));
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.bg-gray-200 {
@ -835,19 +872,8 @@ video {
background-color: rgb(209 213 219 / var(--tw-bg-opacity));
}
.bg-gray-50 {
--tw-bg-opacity: 1;
background-color: rgb(249 250 251 / var(--tw-bg-opacity));
}
.bg-gray-800 {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
}
.bg-white {
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
.p-1 {
padding: 0.25rem;
}
.p-2 {
@ -858,39 +884,36 @@ video {
padding: 1rem;
}
.px-3 {
padding-left: 0.75rem;
padding-right: 0.75rem;
}
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
}
.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
.py-10 {
padding-top: 2.5rem;
padding-bottom: 2.5rem;
}
.py-2 {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
.py-3 {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
}
.py-8 {
padding-top: 2rem;
padding-bottom: 2rem;
}
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
.pb-3 {
padding-bottom: 0.75rem;
}
.pt-2 {
padding-top: 0.5rem;
}
.pt-4 {
padding-top: 1rem;
}
.text-3xl {
@ -916,10 +939,6 @@ video {
font-weight: 500;
}
.font-semibold {
font-weight: 600;
}
.leading-tight {
line-height: 1.25;
}
@ -928,9 +947,9 @@ video {
letter-spacing: -0.025em;
}
.text-gray-200 {
.text-gray-400 {
--tw-text-opacity: 1;
color: rgb(229 231 235 / var(--tw-text-opacity));
color: rgb(156 163 175 / var(--tw-text-opacity));
}
.text-gray-500 {
@ -938,9 +957,9 @@ video {
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.text-gray-700 {
.text-gray-800 {
--tw-text-opacity: 1;
color: rgb(55 65 81 / var(--tw-text-opacity));
color: rgb(31 41 55 / var(--tw-text-opacity));
}
.text-gray-900 {
@ -948,9 +967,19 @@ video {
color: rgb(17 24 39 / var(--tw-text-opacity));
}
.text-white {
.text-gray-200 {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
color: rgb(229 231 235 / var(--tw-text-opacity));
}
.opacity-0 {
opacity: 0;
}
.shadow-lg {
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.shadow {
@ -959,11 +988,31 @@ video {
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.ring-1 {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}
.ring-black {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity));
}
.ring-opacity-5 {
--tw-ring-opacity: 0.05;
}
.hover\:bg-gray-100:hover {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
.hover\:text-gray-500:hover {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.focus\:outline-none:focus {
outline: 2px solid transparent;
outline-offset: 2px;
@ -975,27 +1024,47 @@ video {
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}
.focus\:ring-4:focus {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
.focus\:ring-indigo-500:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));
}
.focus\:ring-gray-200:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(229 231 235 / var(--tw-ring-opacity));
}
.focus\:ring-gray-300:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(209 213 219 / var(--tw-ring-opacity));
.focus\:ring-offset-2:focus {
--tw-ring-offset-width: 2px;
}
@media (min-width: 640px) {
.sm\:-my-px {
margin-top: -1px;
margin-bottom: -1px;
}
.sm\:ml-6 {
margin-left: 1.5rem;
}
.sm\:flex {
display: flex;
}
.sm\:hidden {
display: none;
}
.sm\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.sm\:items-center {
align-items: center;
}
.sm\:space-x-8 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(2rem * var(--tw-space-x-reverse));
margin-left: calc(2rem * calc(1 - var(--tw-space-x-reverse)));
}
.sm\:px-6 {
padding-left: 1.5rem;
padding-right: 1.5rem;
@ -1003,91 +1072,28 @@ video {
}
@media (min-width: 768px) {
.md\:order-1 {
order: 1;
}
.md\:order-2 {
order: 2;
}
.md\:me-0 {
margin-inline-end: 0px;
}
.md\:mt-0 {
margin-top: 0px;
}
.md\:flex {
display: flex;
}
.md\:hidden {
display: none;
}
.md\:h-64 {
height: 16rem;
}
.md\:w-auto {
width: auto;
}
.md\:flex-row {
flex-direction: row;
}
.md\:space-x-0 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0px * var(--tw-space-x-reverse));
margin-left: calc(0px * calc(1 - var(--tw-space-x-reverse)));
}
.md\:space-x-8 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(2rem * var(--tw-space-x-reverse));
margin-left: calc(2rem * calc(1 - var(--tw-space-x-reverse)));
}
.md\:border-0 {
border-width: 0px;
}
.md\:bg-transparent {
background-color: transparent;
}
.md\:bg-white {
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.md\:p-0 {
padding: 0px;
.md\:h-72 {
height: 18rem;
}
.md\:p-6 {
padding: 1.5rem;
}
.md\:text-blue-700 {
--tw-text-opacity: 1;
color: rgb(29 78 216 / var(--tw-text-opacity));
}
.md\:hover\:bg-transparent:hover {
background-color: transparent;
}
.md\:hover\:text-blue-700:hover {
--tw-text-opacity: 1;
color: rgb(29 78 216 / var(--tw-text-opacity));
}
}
@media (min-width: 1024px) {
.lg\:block {
display: block;
}
.lg\:hidden {
display: none;
}
.lg\:grid-cols-4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
@ -1098,16 +1104,7 @@ video {
}
}
.rtl\:space-x-reverse:where([dir="rtl"], [dir="rtl"] *) > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 1;
}
@media (prefers-color-scheme: dark) {
.dark\:divide-gray-600 > :not([hidden]) ~ :not([hidden]) {
--tw-divide-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-divide-opacity));
}
.dark\:border-gray-600 {
--tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity));
@ -1123,26 +1120,6 @@ video {
background-color: rgb(55 65 81 / var(--tw-bg-opacity));
}
.dark\:bg-gray-800 {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
}
.dark\:bg-gray-900 {
--tw-bg-opacity: 1;
background-color: rgb(17 24 39 / var(--tw-bg-opacity));
}
.dark\:text-gray-200 {
--tw-text-opacity: 1;
color: rgb(229 231 235 / var(--tw-text-opacity));
}
.dark\:text-gray-400 {
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
}
.dark\:text-gray-600 {
--tw-text-opacity: 1;
color: rgb(75 85 99 / var(--tw-text-opacity));
@ -1152,52 +1129,4 @@ video {
--tw-text-opacity: 1;
color: rgb(55 65 81 / var(--tw-text-opacity));
}
.dark\:text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.dark\:hover\:bg-gray-600:hover {
--tw-bg-opacity: 1;
background-color: rgb(75 85 99 / var(--tw-bg-opacity));
}
.dark\:hover\:bg-gray-700:hover {
--tw-bg-opacity: 1;
background-color: rgb(55 65 81 / var(--tw-bg-opacity));
}
.dark\:hover\:text-white:hover {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.dark\:focus\:ring-gray-600:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(75 85 99 / var(--tw-ring-opacity));
}
}
@media (min-width: 768px) {
@media (prefers-color-scheme: dark) {
.md\:dark\:bg-gray-900 {
--tw-bg-opacity: 1;
background-color: rgb(17 24 39 / var(--tw-bg-opacity));
}
.md\:dark\:text-blue-500 {
--tw-text-opacity: 1;
color: rgb(59 130 246 / var(--tw-text-opacity));
}
.md\:dark\:hover\:bg-transparent:hover {
background-color: transparent;
}
.md\:dark\:hover\:text-blue-500:hover {
--tw-text-opacity: 1;
color: rgb(59 130 246 / var(--tw-text-opacity));
}
}
}

View File

@ -1,18 +0,0 @@
{% set selected = item.id == current %}
<li>
<a
href="{{ item.href }}"
{% if selected -%}
class="block py-2 px-3 text-white bg-blue-700 rounded md:bg-transparent md:text-blue-700 md:p-0 md:dark:text-blue-500"
aria-current="page"
{% else -%}
class="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700"
{% endif -%}
hx-get="{{ item.href }}"
hx-push-url="true"
hx-swap="outerHTML"
hx-select-oob="#menu-items,#page-header,#page-main"
>
{{ item.label }}
</a>
</li>

View File

@ -1,50 +0,0 @@
{% macro navbar(current) %}
{% let items=crate::menu::get_menu_items() %}
<nav class="bg-white border-gray-200 dark:bg-gray-900">
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
<a href="/" class="flex items-center space-x-3 rtl:space-x-reverse">
<img src="https://flowbite.com/docs/images/logo.svg" class="h-8" alt="Flowbite Logo" />
<span class="self-center text-2xl font-semibold whitespace-nowrap dark:text-white">Krys4lide</span>
</a>
<div class="flex items-center md:order-2 space-x-3 md:space-x-0 rtl:space-x-reverse">
<button type="button" class="flex text-sm bg-gray-800 rounded-full md:me-0 focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600" id="user-menu-button" aria-expanded="false" data-dropdown-toggle="user-dropdown" data-dropdown-placement="bottom">
<span class="sr-only">Ouvrir le menu de profil</span>
<img class="w-8 h-8 rounded-full" src="https://flowbite.com/docs/images/people/profile-picture-3.jpg" alt="user photo">
</button>
<!-- Dropdown menu -->
<div class="z-50 hidden my-4 text-base list-none bg-white divide-y divide-gray-100 rounded-lg shadow dark:bg-gray-700 dark:divide-gray-600" id="user-dropdown">
<div class="px-4 py-3">
<span class="block text-sm text-gray-900 dark:text-white">Bonnie Green</span>
<span class="block text-sm text-gray-500 truncate dark:text-gray-400">name@flowbite.com</span>
</div>
<ul class="py-2" aria-labelledby="user-menu-button">
<li>
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Profile</a>
</li>
<li>
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Settings</a>
</li>
<li>
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Sign out</a>
</li>
</ul>
</div>
<button data-collapse-toggle="navbar-user" type="button" class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600" aria-controls="navbar-user" aria-expanded="false">
<span class="sr-only">Ouvrir le menu de navigation</span>
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15"/>
</svg>
</button>
</div>
<div class="items-center justify-between hidden w-full md:flex md:w-auto md:order-1" id="navbar-user">
<ul id="menu-items" class="flex flex-col font-medium p-4 md:p-0 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:space-x-8 rtl:space-x-reverse md:flex-row md:mt-0 md:border-0 md:bg-white dark:bg-gray-800 md:dark:bg-gray-900 dark:border-gray-700">
{% for item in items %}
{% include "navbar/menu-item.html" %}
{% endfor %}
</ul>
</div>
</div>
</nav>
{% endmacro %}

View File

@ -1,21 +1,29 @@
use std::path::PathBuf;
use axum::http::{StatusCode, Uri};
use axum_htmx::AutoVaryLayer;
use tower_http::services::ServeDir;
mod menu;
mod pages;
mod templates;
use std::path::Path;
use askama_axum::Template;
use axum::http::{StatusCode, Uri};
use tower_http::services::ServeDir;
async fn fallback(uri: Uri) -> (StatusCode, String) {
(StatusCode::NOT_FOUND, format!("No route for {uri}"))
}
pub async fn get_router(assets_path: PathBuf) -> axum::Router<()> {
#[derive(Template)]
#[template(path = "index.html")]
pub struct GetIndexTemplate;
async fn root() -> GetIndexTemplate {
GetIndexTemplate {}
}
pub fn get_router(assets_path: &Path) -> axum::Router {
axum::Router::new()
.nest_service("/assets", ServeDir::new(assets_path))
.merge(pages::get_routes())
.route("/", axum::routing::get(root))
.nest("/pages", pages::get_routes())
.merge(templates::get_routes())
.fallback(fallback)
// The AutoVaryLayer is used to avoid cache issues with htmx (cf: https://github.com/robertwayne/axum-htmx?tab=readme-ov-file#auto-caching-management)
.layer(AutoVaryLayer)
}

View File

@ -1,27 +1,14 @@
use std::path::{Path, PathBuf};
use std::{env, io};
use ::app::get_router;
use axum::body::Body;
use axum::http::Request;
use listenfd::ListenFd;
use notify::Watcher;
use thiserror::Error;
use std::env;
use std::path::Path;
use tokio::net::TcpListener;
use tower_livereload::predicate::Predicate;
use tower_livereload::LiveReloadLayer;
use ::app::get_router;
#[derive(Error, Debug)]
pub enum AppError {
#[error("Unable to bind to TCP listener")]
TCPListener(#[from] std::io::Error),
#[error("Error with the notify watcher")]
NotifyWatcher(#[from] notify::Error),
#[error("Missing environment variable {var}")]
MissingEnvVar { var: &'static str },
}
/// Nous filtrons les requêtes de `htmx` pour ne pas inclure le script _JS_ qui gère le rechargement
/// Voir https://github.com/leotaku/tower-livereload/pull/3
#[derive(Copy, Clone)]
@ -33,52 +20,44 @@ impl<T> Predicate<Request<T>> for NotHtmxPredicate {
}
const DEFAULT_LISTENER: &str = "localhost:3000";
async fn get_tcp_listener() -> Result<TcpListener, io::Error> {
async fn get_tcp_listener() -> TcpListener {
let mut listenfd = ListenFd::from_env();
match listenfd.take_tcp_listener(0)? {
match listenfd.take_tcp_listener(0).unwrap() {
// if we are given a tcp listener on listen fd 0, we use that one
Some(listener) => {
listener.set_nonblocking(true)?;
Ok(TcpListener::from_std(listener)?)
listener.set_nonblocking(true).unwrap();
TcpListener::from_std(listener).unwrap()
}
// otherwise fall back to local listening
None => Ok(TcpListener::bind(DEFAULT_LISTENER).await?),
None => TcpListener::bind(DEFAULT_LISTENER).await.unwrap(),
}
}
fn get_livereload_layer(
templates_paths: Vec<PathBuf>,
) -> Result<LiveReloadLayer<NotHtmxPredicate>, notify::Error> {
fn get_livereload_layer(templates_path: &Path) -> LiveReloadLayer<NotHtmxPredicate> {
let livereload = LiveReloadLayer::new();
let reloader = livereload.reloader();
let mut watcher = notify::recommended_watcher(move |_| reloader.reload())?;
for templates_path in templates_paths {
watcher.watch(templates_path.as_path(), notify::RecursiveMode::Recursive)?;
}
Ok(livereload.request_predicate::<Body, NotHtmxPredicate>(NotHtmxPredicate))
let mut watcher = notify::recommended_watcher(move |_| reloader.reload()).unwrap();
watcher
.watch(templates_path, notify::RecursiveMode::Recursive)
.unwrap();
livereload.request_predicate::<Body, NotHtmxPredicate>(NotHtmxPredicate)
}
#[tokio::main]
async fn main() -> Result<(), AppError> {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").map_err(|_| AppError::MissingEnvVar {
var: "CARGO_MANIFEST_DIR",
})?;
async fn main() {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let assets_path = Path::new(&manifest_dir).join("assets");
let templates_paths = vec![
Path::new(&manifest_dir).join("src/pages"),
Path::new(&manifest_dir).join("src/components"),
];
let templates_path = Path::new(&manifest_dir).join("templates");
let livereload_layer =
get_livereload_layer(templates_paths).map_err(AppError::NotifyWatcher)?;
let router = get_router(assets_path).await.layer(livereload_layer);
let livereload_layer = get_livereload_layer(&templates_path);
let router = get_router(assets_path.as_path()).layer(livereload_layer);
let listener: TcpListener = get_tcp_listener().await.map_err(AppError::TCPListener)?;
let local_addr = listener.local_addr().map_err(AppError::TCPListener)?;
println!("Listening on: http://{}", local_addr);
let listener: TcpListener = get_tcp_listener().await;
println!("Listening on: http://{}", listener.local_addr().unwrap());
// Run the server with the router
axum::serve(listener, router.into_make_service()).await?;
Ok(())
axum::serve(listener, router.into_make_service())
.await
.unwrap();
}

View File

@ -1,23 +0,0 @@
pub struct MenuItem {
pub id: String,
pub label: String,
pub href: String,
}
/// Get the menu items
/// This function is the central place to define the menu items
/// It can be used directly in templates, for example in the `navbar` component to render the menu
pub fn get_menu_items() -> Vec<MenuItem> {
vec![
MenuItem {
id: "home".to_string(),
label: "Accueil".to_string(),
href: "/".to_string(),
},
MenuItem {
id: "cps".to_string(),
label: "CPS".to_string(),
href: "/cps".to_string(),
},
]
}

View File

@ -1,43 +0,0 @@
{% extends "base.html" %}
{% import "navbar/navbar.html" as navbar -%}
{% block title %}Pharma Libre - CPS{% endblock %}
{% block body %}
{% call navbar::navbar(current="cps") %}
<div class="py-10">
<header id="page-header">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<h1
id="page-title"
class="text-3xl font-bold leading-tight tracking-tight text-gray-900"
>
CPS
</h1>
</div>
</header>
<main id="page-main">
<div
class="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8"
>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-96 mb-4"
>A</div>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-4">
<div
class="border-2 border-dashed border-gray-300 rounded-lg dark:border-gray-600 h-32 md:h-64"
>B</div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
>C</div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
>D</div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
>E</div>
</div>
</div>
</main>
</div>
{% endblock %}

View File

@ -1,12 +1,9 @@
use askama_axum::Template;
use axum_htmx::HxRequest;
#[derive(Template)]
#[template(path = "cps.html")]
pub struct CpsTemplate {
hx_request: bool,
}
#[template(path = "pages/cps.html")]
pub struct CpsTemplate;
pub async fn cps(HxRequest(hx_request): HxRequest) -> CpsTemplate {
CpsTemplate { hx_request }
pub async fn cps() -> CpsTemplate {
CpsTemplate
}

View File

@ -1,43 +0,0 @@
{% extends "base.html" %}
{% import "navbar/navbar.html" as navbar -%}
{% block title %}Pharma Libre - Accueil{% endblock %}
{% block body %}
{% call navbar::navbar(current="home") %}
<div class="py-10">
<header id="page-header">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<h1
id="page-title"
class="text-3xl font-bold leading-tight tracking-tight text-gray-900"
>
Accueil
</h1>
</div>
</header>
<main id="page-main">
<div
class="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8"
>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-4">
<div
class="border-2 border-dashed border-gray-300 rounded-lg dark:border-gray-600 h-32 md:h-64"
>A</div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
>B</div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
>C</div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
>D</div>
</div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-96 mb-4"
>E</div>
</div>
</main>
</div>
{% endblock %}

View File

@ -1,12 +1,9 @@
use askama_axum::Template;
use axum_htmx::HxRequest;
#[derive(Template)]
#[template(path = "home.html")]
pub struct GetHomeTemplate {
hx_request: bool,
}
#[template(path = "pages/home.html")]
pub struct HomeTemplate;
pub async fn home(HxRequest(hx_request): HxRequest) -> GetHomeTemplate {
GetHomeTemplate { hx_request }
pub async fn home() -> HomeTemplate {
HomeTemplate
}

View File

@ -5,6 +5,6 @@ mod home;
pub fn get_routes() -> Router {
Router::new()
.route("/", routing::get(home::home))
.route("/home", routing::get(home::home))
.route("/cps", routing::get(cps::cps))
}

View File

@ -0,0 +1,18 @@
use askama_axum::Template;
use axum::{routing, Router};
#[derive(Template)]
#[template(path = "hello.html")]
struct HelloTemplate {
pub name: String,
}
async fn hello() -> HelloTemplate {
HelloTemplate {
name: "Theo".to_string(),
}
}
pub fn get_routes() -> Router {
Router::new().route("/", routing::get(hello))
}

View File

@ -0,0 +1,12 @@
use axum::Router;
mod hello;
mod nav;
mod profile;
pub fn get_routes() -> Router {
Router::new()
.nest("/hello", hello::get_routes())
.nest("/nav", nav::get_routes())
.nest("/profile", profile::get_routes())
}

View File

@ -0,0 +1,60 @@
use askama_axum::Template;
use axum::{extract::Query, routing, Router};
use serde::Deserialize;
struct MenuItem {
label: String,
href: String,
current: bool,
}
#[derive(Deserialize)]
struct MenuParameters {
mobile: bool,
}
#[derive(Template)]
#[template(path = "layout/nav/nav-menu-items.html")]
struct MenuTemplate {
mobile: bool,
items: Vec<MenuItem>,
}
impl MenuTemplate {
fn get_classes(&self, is_current_item: &bool) -> String {
let common_classes = match self.mobile {
true => "block border-l-4 py-2 pl-3 pr-4 text-base font-medium".to_string(),
false => {
"inline-flex items-center border-b-2 px-1 pt-1 text-sm font-medium".to_string()
}
};
match (self.mobile, is_current_item) {
(true, true) => common_classes + " border-indigo-500 bg-indigo-50 text-indigo-700",
(true, false) => common_classes + " border-transparent text-gray-600 hover:border-gray-300 hover:bg-gray-50 hover:text-gray-800",
(false, true) => common_classes + " border-indigo-500 text-gray-900",
(false, false) => common_classes + " border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700",
}
}
}
async fn menu(Query(params): Query<MenuParameters>) -> MenuTemplate {
MenuTemplate {
mobile: params.mobile,
items: vec![
MenuItem {
label: "Accueil".to_string(),
href: "/pages/home".to_string(),
current: true,
},
MenuItem {
label: "CPS".to_string(),
href: "/pages/cps".to_string(),
current: false,
},
],
}
}
pub fn get_routes() -> Router {
Router::new().route("/menu", routing::get(menu))
}

View File

@ -0,0 +1,63 @@
use askama_axum::Template;
use axum::{extract::Query, routing, Router};
use serde::Deserialize;
struct MenuItem {
label: String,
id: String,
current: bool,
}
#[derive(Deserialize)]
struct MenuParameters {
mobile: bool,
}
#[derive(Template)]
#[template(path = "layout/nav/profile-menu-items.html")]
struct MenuTemplate {
mobile: bool,
items: Vec<MenuItem>,
}
impl MenuTemplate {
fn get_classes(&self, is_current_item: &bool) -> String {
let common_classes = match self.mobile {
true => "block px-4 py-2 text-base font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-800".to_string(),
false => "block px-4 py-2 text-sm text-gray-700".to_string(),
};
match (self.mobile, is_current_item) {
(true, true) => common_classes + "", // ???
(true, false) => common_classes + "",
(false, true) => common_classes + " bg-gray-100",
(false, false) => common_classes + "",
}
}
}
async fn menu(Query(params): Query<MenuParameters>) -> MenuTemplate {
MenuTemplate {
mobile: params.mobile,
items: vec![
MenuItem {
label: "Votre profil".to_string(),
id: "profile".to_string(),
current: false,
},
MenuItem {
label: "Paramètres".to_string(),
id: "settings".to_string(),
current: false,
},
MenuItem {
label: "Déconnexion".to_string(),
id: "logout".to_string(),
current: false,
},
],
}
}
pub fn get_routes() -> Router {
Router::new().route("/menu", routing::get(menu))
}

View File

@ -1,7 +1,7 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./src/**/*.html',
'./templates/**/*.html',
'./css/**/*.css',
],
theme: {

View File

@ -1,7 +1,3 @@
{% if hx_request %}
<title>{% block title %}{{ title }}{% endblock %}</title>
{% block body %}{% endblock %}
{% else %}
<!doctype html>
<html lang="fr" class="h-full">
<head>
@ -9,15 +5,19 @@
<script src="/assets/js/htmx@2.0.1.min.js"></script>
<script src="/assets/js/alpinejs@3.14.1.min.js" defer></script>
<script src="/assets/js/flowbite@2.5.1.min.js"></script>
<link href="/assets/css/style.css" rel="stylesheet">
<link href="/assets/css/flowbite@2.5.1.min.css" rel="stylesheet" />
<script src="/assets/js/flowbite@2.5.1.min.js"></script>
{% block head %}{% endblock %}
</head>
<body class="h-full">
<div class="min-h-full">
{% block nav %}
{% include "layout/nav.html" %}
{% endblock %}
{% block body %}{% endblock %}
</div>
</body>
</html>
{% endif %}

View File

@ -0,0 +1 @@
<div>Hello {{name}}!</div>

View File

@ -0,0 +1,34 @@
{% extends "base.html" %}
{% block title %}Pharma Libre{% endblock %}
{% block body %}
<div class="py-10">
<header>
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<h1
id="page-title"
class="text-3xl font-bold leading-tight tracking-tight text-gray-900"
>
{% include "skeletons/page-title.html" %}
</h1>
</div>
</header>
<main>
<div
id="main-container"
class="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8"
>
<!-- Your content -->
<div
hx-get="/pages/home"
hx-target="this"
hx-trigger="load"
hx-swap="outerHTML"
>
{% include "skeletons/card.html" %}
</div>
</div>
</main>
</div>
{% endblock %}

View File

@ -0,0 +1,41 @@
<nav
class="border-b border-gray-200 bg-white"
x-data="{ menuOpen: false }"
>
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex h-16 justify-between">
<div class="flex">
{% include "layout/nav/logo.html" %}
<div class="hidden sm:-my-px sm:ml-6 sm:flex sm:space-x-8">
{% include "layout/nav/desktop/menu-items.html" %}
</div>
</div>
<div class="hidden sm:ml-6 sm:flex sm:items-center">
{% include "layout/nav/desktop/notifications-button.html" %}
{% include "layout/nav/desktop/profile.html" %}
</div>
<div class="-mr-2 flex items-center sm:hidden">
{% include "layout/nav/mobile/menu-button.html" %}
</div>
</div>
</div>
<!-- Mobile menu, show/hide based on menu state. -->
<div
class="sm:hidden" id="mobile-menu"
x-show="menuOpen"
x-cloak
>
<div class="space-y-1 pb-3 pt-2">
{% include "layout/nav/mobile/menu-items.html" %}
</div>
<div class="border-t border-gray-200 pb-3 pt-4">
<div class="flex items-center px-4">
{% include "layout/nav/mobile/profile.html" %}
{% include "layout/nav/mobile/notifications-button.html" %}
</div>
<div class="mt-3 space-y-1">
{% include "layout/nav/mobile/profile-items.html" %}
</div>
</div>
</div>
</nav>

View File

@ -0,0 +1,9 @@
<div
id="nav-menu-desktop"
hx-get="/nav/menu?mobile=false"
hx-target="this"
hx-trigger="load"
hx-swap="outerHTML"
>
{% include "skeletons/menu-items.html" %}
</div>

View File

@ -0,0 +1,6 @@
<button
type="button"
class="relative rounded-full bg-white p-1 text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
>
{% include "layout/nav/notifications-icon.html" %}
</button>

View File

@ -0,0 +1,22 @@
<div
class="absolute right-0 z-10 mt-2 w-48 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
role="menu"
id="profile-dropdown"
aria-orientation="vertical"
aria-labelledby="user-menu-button"
tabindex="-1"
x-show="profileOpen"
x-on:click.outside="profileOpen = false"
x-cloak
x-transition
>
<div
id="profile-menu-desktop"
hx-get="/profile/menu?mobile=false"
hx-target="this"
hx-trigger="load"
hx-swap="outerHTML"
>
Chargement ...
</div>
</div>

View File

@ -0,0 +1,27 @@
<!-- Profile dropdown -->
<div
class="relative ml-3"
x-data="{ profileOpen: false }"
>
<div>
<button
type="button"
class="relative flex max-w-xs items-center rounded-full bg-white text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
id="user-menu-button"
aria-controls="profile-dropdown"
aria-expanded="false"
aria-haspopup="menu"
x-on:click="profileOpen = ! profileOpen"
>
<span class="absolute -inset-1.5"></span>
<span class="sr-only">Open user menu</span>
<img
class="h-8 w-8 rounded-full"
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
alt=""
/>
</button>
</div>
{% include "layout/nav/desktop/profile-dropdown.html" %}
</div>

View File

@ -0,0 +1,4 @@
<div class="flex flex-shrink-0 items-center">
<img class="block h-8 w-auto lg:hidden" src="https://tailwindui.com/img/logos/mark.svg?color=indigo&shade=600" alt="Your Company">
<img class="hidden h-8 w-auto lg:block" src="https://tailwindui.com/img/logos/mark.svg?color=indigo&shade=600" alt="Your Company">
</div>

View File

@ -0,0 +1,43 @@
<!-- Mobile menu button -->
<button
type="button"
class="relative inline-flex items-center justify-center rounded-md bg-white p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
aria-controls="mobile-menu"
x-on:click="menuOpen = ! menuOpen"
x-bind:aria-expanded="menuOpen"
>
<span class="absolute -inset-0.5"></span>
<span class="sr-only">Open main menu</span>
<!-- Menu open: "hidden", Menu closed: "block" -->
<svg
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
x-bind:class="menuOpen ? 'hidden' : 'block'"
x-bind:aria-hidden="menuOpen"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
/>
</svg>
<!-- Menu open: "block", Menu closed: "hidden" -->
<svg
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
x-bind:class="menuOpen ? 'block' : 'hidden'"
x-bind:aria-hidden="! menuOpen"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>

View File

@ -0,0 +1,9 @@
<div
id="nav-menu-mobile"
hx-get="/nav/menu?mobile=true"
hx-target="this"
hx-trigger="load"
hx-swap="outerHTML"
>
Chargement ...
</div>

View File

@ -0,0 +1,6 @@
<button
type="button"
class="relative ml-auto flex-shrink-0 rounded-full bg-white p-1 text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
>
{% include "layout/nav/notifications-icon.html" %}
</button>

View File

@ -0,0 +1,9 @@
<div
id="profile-menu-mobile"
hx-get="/profile/menu?mobile=true"
hx-target="this"
hx-trigger="load"
hx-swap="outerHTML"
>
Chargement ...
</div>

View File

@ -0,0 +1,11 @@
<div class="flex-shrink-0">
<img
class="h-10 w-10 rounded-full"
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
alt=""
/>
</div>
<div class="ml-3">
<div class="text-base font-medium text-gray-800">Tom Cook</div>
<div class="text-sm font-medium text-gray-500">tom@example.com</div>
</div>

View File

@ -0,0 +1,13 @@
{% for item in items %}
<a
href=""
hx-get="{{ item.href }}"
hx-trigger="click"
hx-target="#main-container"
hx-swap="innerHTML"
class="{{ Self::get_classes(self, item.current) }}"
aria-current="{% if item.current %}page{% endif %}"
>
{{ item.label }}
</a>
{% endfor %}

View File

@ -0,0 +1,16 @@
<span class="absolute -inset-1.5"></span>
<span class="sr-only">View notifications</span>
<svg
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0"
/>
</svg>

View File

@ -0,0 +1,11 @@
{% for item in items %}
<a
href="#{{ item.id }}"
class="{{ Self::get_classes(self, item.current) }}"
role="menuitem"
tabindex="-1"
id="{{ item.id }}"
>
{{ item.label }}
</a>
{% endfor %}

View File

@ -0,0 +1,52 @@
<h3 id="page-title" hx-swap-oob="textContent">
CPS
</h3>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-4">
<div
class="border-2 border-dashed border-gray-300 rounded-lg dark:border-gray-600 h-32 md:h-64"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
></div>
</div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-96 mb-4"
></div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
</div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-96 mb-4"
></div>
<div class="grid grid-cols-2 gap-4">
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
</div>

View File

@ -0,0 +1,52 @@
<h3 id="page-title" hx-swap-oob="textContent">
Accueil
</h3>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-4">
<div
class="border-2 border-dashed border-gray-300 rounded-lg dark:border-gray-600 h-32 md:h-64"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
></div>
</div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-96 mb-4"
></div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
</div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-96 mb-4"
></div>
<div class="grid grid-cols-2 gap-4">
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
<div
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
></div>
</div>

View File

@ -1,14 +0,0 @@
[package]
name = "backend"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.89"
axum = "0.7.6"
listenfd = "1.0.1"
tokio = { version = "1.40.0", features = ["macros", "rt-multi-thread"] }
[dev-dependencies]
cargo-watch = "8.5.2"
systemfd = "0.4.3"

View File

@ -1,19 +0,0 @@
# Backend
Ceci est un serveur backend, basé sur axum, et permettant d'offrir une gestion centralisée des accès aux données.
## Prérequis
En développement, le mécanisme de hot-reload nécessite de disposer de `cargo-watch` et `systemfd`. Pour les installer, exécutez la commande suivante :
```bash
cargo install cargo-watch systemfd
```
## Développement
Pour lancer le serveur en mode développement, exécutez la commande suivante :
```bash
systemfd --no-pid -s http::3030 -- cargo watch -x 'run --bin backend'
```

View File

@ -1,37 +0,0 @@
use anyhow::Error as AnyError;
use axum::http::{StatusCode, Uri};
use axum::response::{IntoResponse, Response};
use axum::{routing::get, Router};
pub fn get_router() -> Router {
Router::new()
.route("/", get(|| async { "Hello, world!" }))
.fallback(fallback)
}
async fn fallback(uri: Uri) -> (StatusCode, String) {
(StatusCode::NOT_FOUND, format!("No route for {uri}"))
}
struct AppError(AnyError);
// To automatically convert `AppError` into a response
impl IntoResponse for AppError {
fn into_response(self) -> Response {
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("Internal Server Error: {}", self.0),
)
.into_response()
}
}
// To automatically convert `AnyError` into `AppError`
impl<E> From<E> for AppError
where
E: Into<AnyError>,
{
fn from(err: E) -> Self {
Self(err.into())
}
}

View File

@ -1,24 +0,0 @@
use listenfd::ListenFd;
use tokio::net::TcpListener;
use backend::get_router;
#[tokio::main]
async fn main() {
let app = get_router();
let mut listenfd = ListenFd::from_env();
let listener = match listenfd.take_tcp_listener(0).unwrap() {
// if we are given a tcp listener on listen fd 0, we use that one
Some(listener) => {
listener.set_nonblocking(true).unwrap();
TcpListener::from_std(listener).unwrap()
}
// otherwise fall back to local listening
None => TcpListener::bind("0.0.0.0:8080").await.unwrap(),
};
println!("Listening on {}", listener.local_addr().unwrap());
axum::serve(listener, app).await.unwrap();
}

View File

@ -10,11 +10,15 @@ name = "desktop_lib"
crate-type = ["lib", "cdylib", "staticlib"]
[build-dependencies]
tauri-build = { version = "2.0.0-rc", features = [] }
tauri-build = { version = "2.0.0-beta", features = [] }
[dependencies]
tauri = { version = "2.0.0-rc", features = [] }
tauri-plugin-shell = "2.0.0-rc"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
axum = "0.7.5"
tauri = { version = "2.0.0-beta", features = [] }
tower = "0.4.13"
tokio = "1.39.1"
app = { path = "../app" }
http = "1.1.0"
bytes = "1.6.1"

View File

@ -1,10 +0,0 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"core:default",
"shell:allow-open"
]
}

View File

@ -1,14 +1,69 @@
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
use bytes::Bytes;
use http::{request, response, Request, Response};
use std::path::PathBuf;
use std::sync::Arc;
use axum::body::{to_bytes, Body};
use axum::Router;
use tauri::path::BaseDirectory;
use tauri::Manager;
use tokio::sync::{Mutex, MutexGuard};
use tower::{Service, ServiceExt};
async fn process_tauri_request(
tauri_request: Request<Vec<u8>>,
mut router: MutexGuard<'_, Router>,
) -> Response<Vec<u8>> {
let (parts, body): (request::Parts, Vec<u8>) = tauri_request.into_parts();
let axum_request: Request<Body> = Request::from_parts(parts, body.into());
let axum_response: Response<Body> = router
.as_service()
.ready()
.await
.expect("Failed to get ready service from router")
.call(axum_request)
.await
.expect("Could not get response from router");
let (parts, body): (response::Parts, Body) = axum_response.into_parts();
let body: Bytes = to_bytes(body, usize::MAX).await.unwrap_or_default();
let tauri_response: Response<Vec<u8>> = Response::from_parts(parts, body.into());
tauri_response
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.invoke_handler(tauri::generate_handler![greet])
.setup(|app| {
let assets_path: PathBuf = app
.path()
.resolve("assets", BaseDirectory::Resource)
.expect("Path should be resolvable");
// Adds Axum router to application state
// This makes it so we can retrieve it from any app instance (see bellow)
let router = Arc::new(Mutex::new(app::get_router(&assets_path)));
app.manage(router);
Ok(())
})
.register_asynchronous_uri_scheme_protocol("axum", move |app, request, responder| {
// Retrieve the router from the application state and clone it for the async block
let router = Arc::clone(&app.state::<Arc<Mutex<axum::Router>>>());
// Spawn a new async task to process the request
tauri::async_runtime::spawn(async move {
let router = router.lock().await;
let response = process_tauri_request(request, router).await;
responder.respond(response);
});
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View File

@ -1,24 +1,20 @@
{
"$schema": "https://schema.tauri.app/config/2.0.0-rc",
"productName": "Chrys4lide LGO",
"productName": "Logiciel Pharma",
"version": "0.0.1",
"identifier": "org.p4pillon.chrys4lide.lgo",
"identifier": "org.p4pillon.pharma.desktop",
"build": {
"beforeDevCommand": {
"cwd": "../../frontend",
"script": "bun run dev"
"cwd": "../app",
"script": "cargo run"
},
"devUrl": "http://localhost:1420",
"beforeBuildCommand": {
"cwd": "../../frontend",
"script": "bun run generate"
},
"frontendDist": "../../frontend/dist"
"devUrl": "http://localhost:3000",
"frontendDist": "axum://place.holder/"
},
"app": {
"withGlobalTauri": true,
"windows": [
{
"title": "Chrys4lide | LG0",
"title": "Logiciel Pharma",
"width": 800,
"height": 600
}
@ -29,6 +25,9 @@
},
"bundle": {
"active": true,
"resources": {
"../app/assets/": "./assets/"
},
"targets": "all",
"icon": [
"icons/32x32.png",
@ -38,4 +37,5 @@
"icons/icon.ico"
]
}
}

View File

@ -1,17 +0,0 @@
[package]
name = "fsv-sys"
version = "0.1.0"
edition = "2021"
links = "ssvlux64,ssvosx,Ssvw64"
# Linux: Libssvlux64.so
# Windows: Ssvw64.dll
# macOS: ssvosx.framework
[dependencies]
libc = "0.2.159"
libloading = "0.8.5"
thiserror = "1.0.64"
[build-dependencies]
bindgen = "0.70.1"

View File

@ -1,23 +0,0 @@
# FSV-sys, bindings Rust pour le package FSV SESAM-Vitale
## Utilisation
### Pré-requis
- Installer le [package FSV](https://industriels.sesam-vitale.fr/group/fournitures-sesam-vitale)
- Les librairies dynamiques (.lib, .dll, ...) fournies ne sont pas installés dans les emplacements standard du système, il faudra donc configurer leur chemin d'installation dans le fichier de configuration `.env.build` (voir ci-dessous)
- Le détail des chemins d'installation est donné dans la documentation du package FSV `fsv-mi-004_pack-FSV1.40.14_V2.3.pdf`
- Linux - par défaut : `/opt/santesocial/fsv/1.40.13/lib`
- Windows - par défaut : `C:\Program Files\santesocial\santesocial\fsv\1.40.14\lib` (ou dans Program Files (x86) si c'est le package 32bits qui a été installé)
- Installer la [CryptolibCPS](https://industriels.sesam-vitale.fr/group/galss-cryptolib-cps)
- Ce package fourni également l'utilitaire "CPS Gestion" pour obtenir des informations sur le lecteur de carte, etc.
- Linux : `cpgeslux`
- Windows : `...`
## Développement
### Pré-requis
- Pour la génération des bindings lors de la pahse de `build` à l'aide de `bindgen`, il est nécessaire d'avoir installé `clang` ([documentation](https://rust-lang.github.io/rust-bindgen/requirements.html)).

View File

@ -1,7 +0,0 @@
#ifndef WRAPPER_LINUX_H
#define WRAPPER_LINUX_H
#include "../../vendor/fsv/1.40.14.13/includes/SYS_DEF/linux/mc_sys_def.h"
#include "../../vendor/fsv/1.40.14.13/includes/SSV/pourFSV1.40.13/ssv.h"
#endif // WRAPPER_LINUX_H

View File

@ -1,7 +0,0 @@
#ifndef WRAPPER_MACOSX_H
#define WRAPPER_MACOSX_H
#include "../../vendor/fsv/1.40.14.13/includes/SYS_DEF/macosx/mc_sys_def.h"
#include "../../vendor/fsv/1.40.14.13/includes/SSV/pourFSV1.40.13/ssv.h"
#endif // WRAPPER_MACOSX_H

View File

@ -1,7 +0,0 @@
#ifndef WRAPPER_WIN_H
#define WRAPPER_WIN_H
#include "../../vendor/fsv/1.40.14.13/includes/SYS_DEF/win/mc_sys_def.h"
#include "../../vendor/fsv/1.40.14.13/includes/SSV/pourFSV1.40.13/ssv.h"
#endif // WRAPPER_WIN_H

View File

@ -1,7 +0,0 @@
#ifndef WRAPPER_LINUX_H
#define WRAPPER_LINUX_H
#include "../../vendor/fsv/1.40.14.13/includes/SYS_DEF/linux/mc_sys_def.h"
#include "../../vendor/fsv/1.40.14.13/includes/SSV/pourFSV1.40.14/ssv.h"
#endif // WRAPPER_LINUX_H

View File

@ -1,7 +0,0 @@
#ifndef WRAPPER_MACOSX_H
#define WRAPPER_MACOSX_H
#include "../../vendor/fsv/1.40.14.13/includes/SYS_DEF/macosx/mc_sys_def.h"
#include "../../vendor/fsv/1.40.14.13/includes/SSV/pourFSV1.40.14/ssv.h"
#endif // WRAPPER_MACOSX_H

View File

@ -1,7 +0,0 @@
#ifndef WRAPPER_WIN_H
#define WRAPPER_WIN_H
#include "../../vendor/fsv/1.40.14.13/includes/SYS_DEF/win/mc_sys_def.h"
#include "../../vendor/fsv/1.40.14.13/includes/SSV/pourFSV1.40.14/ssv.h"
#endif // WRAPPER_WIN_H

View File

@ -1,57 +0,0 @@
use std::{env, path::PathBuf};
// Supported versions of FSV
static SUPPORTED_FSV_VERSIONS: [&str; 2] = ["1.40.14", "1.40.13"];
fn build_bindings(version: &str, target_code: &str) -> PathBuf {
let target = env::var("TARGET").expect("TARGET not set");
let wrapper_path = format!("bindgen-wrappers/{}/wrapper.{}.h", version, target_code);
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header(wrapper_path)
// To generate the bindings for specific target
.clang_arg(format!("--target={}", target))
// Limit the bindings generation to the SSV_ prefix
.allowlist_item("SSV_.*")
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let out_file = format!("bindings_{}.rs", version);
let out_path = out_dir.join(out_file);
bindings
.write_to_file(&out_path)
.expect("Couldn't write bindings! ");
out_path
}
fn get_target_code() -> String {
// Use CARGO configuration env Variable, because !cfg(target_os) is not available in build.rs
// Source: https://kazlauskas.me/entries/writing-proper-buildrs-scripts
let target_os = env::var("CARGO_CFG_TARGET_OS");
match target_os.as_ref().map(|x| &**x) {
Ok("linux") => "linux", // lib_name = "ssvlux64";
Ok("windows") => "win", // lib_name = "Ssvw64";
Ok("macos") => "macosx", // lib_name = "ssvosx";
tos => panic!("Unsupported target_os {:?}", tos),
}
.to_string()
}
fn main() {
let target_code = get_target_code();
// Build the bindings for each supported version of FSV
let bindings_paths: Vec<PathBuf> = SUPPORTED_FSV_VERSIONS
.iter()
.map(|version| build_bindings(version, &target_code))
.collect();
println!("FSV bindings generated: {:#?}", bindings_paths);
}

View File

@ -1,169 +0,0 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#[derive(Debug)]
pub enum SUPPORTED_FSV_VERSIONS {
V1_40_14, // 1.40.14
V1_40_13, // 1.40.13
}
impl SUPPORTED_FSV_VERSIONS {
fn as_str(&self) -> &'static str {
match self {
Self::V1_40_14 => "1.40.14",
Self::V1_40_13 => "1.40.13",
}
}
}
pub mod BINDINGS {
include!(concat!(env!("OUT_DIR"), "/bindings_1.40.13.rs"));
}
// We need to keep the this use statement to get `ssv_function` macro working well
use BINDINGS::*;
/// Macro to generate a function that implements a call to an external function in BINDINGS
macro_rules! ssv_function {
($binding:ty, $func_name:ident, {$($arg_name:ident: $arg_type:ty),*}) => {
/// # Safety
/// This function is unsafe because it calls an external function through FFI.
/// The caller must ensure that the provided arguments are valid and that the
/// external function is safe to call.
pub unsafe fn $func_name(&self, $($arg_name: $arg_type),*) -> Result<u16, Error> {
let func_struct: libloading::Symbol<'_, $binding> =
unsafe { self.library.get(stringify!($binding).as_bytes())? };
let func = match *func_struct {
Some(func) => func,
None => return Err(Error::SymbolMissing(stringify!($binding))),
};
Ok(func($($arg_name),*))
}
};
}
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
LibLoading(#[from] libloading::Error),
#[error("Symbol missing: {0}")]
SymbolMissing(&'static str),
}
/// Wrapper around the SESAM-VITALE library
/// This struct is responsible for loading the library and providing an interface to call its functions.
/// The library is loaded at creation and kept in memory until the struct is dropped.
#[derive(Debug)]
pub struct SSVLibrary {
version: SUPPORTED_FSV_VERSIONS,
library: libloading::Library,
}
fn get_library_name() -> &'static str {
// TODO : Use libloading::library_filename to get platform-specific filename ?
"libssvlux64.so"
}
fn get_library_root_path() -> &'static str {
"/opt/santesocial/fsv"
}
fn get_sesam_ini_root_path() -> &'static str {
"/etc/opt/santesocial/fsv"
}
impl SSVLibrary {
pub fn new(version: SUPPORTED_FSV_VERSIONS) -> Result<Self, Error> {
let library_path = Self::get_library_path(&version);
let library = unsafe { libloading::Library::new(library_path)? };
Ok(SSVLibrary { version, library })
}
pub fn library(&self) -> &libloading::Library {
&self.library
}
pub fn sesam_ini_path(&self) -> String {
let root_path = get_sesam_ini_root_path();
let version = self.version.as_str();
format!("{root_path}/{version}/conf/sesam.ini")
}
pub fn get_library_path(version: &SUPPORTED_FSV_VERSIONS) -> String {
let root_path = get_library_root_path();
let library_name = get_library_name();
let version = version.as_str();
format!("{root_path}/{version}/lib/{library_name}")
}
ssv_function!(SSV_InitLIB2, ssv_init_lib2, {
pcFichierSesam: *const i8
});
ssv_function!(SSV_LireConfig, ssv_lire_config, {
pZDataOut: *mut *mut libc::c_void,
psTailleDataOut: *mut usize
});
ssv_function!(SSV_LireCartePS, ssv_lire_carte_ps, {
NomRessourcePS: *const i8,
NomRessourceLecteur: *const i8,
CodePorteurPS: *const i8,
pZDataOut: *mut *mut libc::c_void,
pTailleZone: *mut usize
});
}
#[cfg(test)]
mod test {
use std::{ffi::CString, ptr};
use super::*;
#[test]
fn test_initlib2() {
let ssv_library =
SSVLibrary::new(SUPPORTED_FSV_VERSIONS::V1_40_13).expect("SSVLibrary::new failed");
let sesam_ini_str =
CString::new(ssv_library.sesam_ini_path()).expect("CString::new failed");
let result = unsafe { ssv_library.ssv_init_lib2(sesam_ini_str.as_ptr()) }.unwrap();
assert_eq!(result, 0);
}
#[test]
fn test_lire_config_and_carte_ps() {
let ssv_library =
SSVLibrary::new(SUPPORTED_FSV_VERSIONS::V1_40_13).expect("SSVLibrary::new failed");
let sesam_ini_str =
CString::new(ssv_library.sesam_ini_path()).expect("CString::new failed");
let result = unsafe { ssv_library.ssv_init_lib2(sesam_ini_str.as_ptr()) }.unwrap();
assert_eq!(result, 0);
let mut buffer_ptr: *mut libc::c_void = ptr::null_mut();
let mut size: libc::size_t = 0;
let result = unsafe { ssv_library.ssv_lire_config(&mut buffer_ptr, &mut size) }.unwrap();
assert_eq!(result, 0);
let nom_ressource_ps =
CString::new("Gemalto PC Twin Reader (645D94C3) 00 00").expect("CString::new failed");
let nom_ressource_lecteur =
CString::new("Gemalto PC Twin Reader (645D94C3) 00 00").expect("CString::new failed");
let code_porteur_ps = CString::new("1234").expect("CString::new failed");
let mut buffer_ptr: *mut libc::c_void = ptr::null_mut();
let mut size: libc::size_t = 0;
let result = unsafe {
ssv_library.ssv_lire_carte_ps(
nom_ressource_ps.as_ptr(),
nom_ressource_lecteur.as_ptr(),
code_porteur_ps.as_ptr(),
&mut buffer_ptr,
&mut size,
)
}
.unwrap();
assert_eq!(result, 0);
}
}

View File

@ -1,123 +0,0 @@
/*
* -------------------------------------------------------------------
* (c) 2001 GIE SESAM-VITALE
*
* PROJET : Services de Gestion de Donnees
*
* FICHIER : sgd.h (v4)
*
* Declaration des prototypes des fonctions SGD pour les progiciels.
* -------------------------------------------------------------------
*/
#ifndef __SGD_H__
#define __SGD_H__
#ifdef __cplusplus
extern "C" {
#endif
/*
* Inclusions
*/
#include <stddef.h>
#include "mc_sys_def.h"
/* Reservation d'un session d'echange. */
extern unsigned short API_ENTRY SGD_ReserverSession (size_t Taille, unsigned short* NumeroSession);
/* Redimensionnement d'une zone d'entree interne. */
extern unsigned short API_ENTRY
SGD_RedimensionnerBuffer (unsigned short NumeroSession,
size_t NouvelleTaille);
/* Liberation d'une session d'echange. */
extern unsigned short API_ENTRY
SGD_LibererSession (unsigned short NumeroSession);
/* Ajout d'un groupe. */
extern unsigned short API_ENTRY
SGD_AjouterGroupe (unsigned short NumeroSession,
unsigned short IdGroupe);
/* Ajout d'un champ. */
extern unsigned short API_ENTRY
SGD_AjouterChamp (unsigned short NumeroSession,
const char* ValeurChamp);
/* Ajout d'un champ d'octets. */
extern unsigned short API_ENTRY
SGD_AjouterChampBin (unsigned short NumeroSession,
const char* ValeurChamp,
size_t TailleChamp);
/* Ajout d'un champ d'octets d'un Fichier. */
extern unsigned short API_ENTRY
SGD_AjouterChampFichier (unsigned short NumeroSession,
const char* NomFichier);
/* Lecture du numero du groupe suivant. */
extern unsigned short API_ENTRY
SGD_LireGroupeSuivant (unsigned short NumeroSession,
unsigned short IdGroupeCourant,
unsigned short OccurrenceGroupeCourant,
unsigned short* IdGroupeSuivant,
unsigned short* OccurrenceGroupeSuivant);
/* Lecture d'un champ. */
extern unsigned short API_ENTRY
SGD_LireChamp (unsigned short NumeroSession,
unsigned short IdGroupe,
unsigned short OccurrenceGroupe,
unsigned short NumeroChamp,
char* ValeurChamp,
size_t* TailleMax);
/* Lecture d'un champ d'octets. */
extern unsigned short API_ENTRY
SGD_LireChampBin (unsigned short NumeroSession,
unsigned short IdGroupe,
unsigned short OccurrenceGroupe,
unsigned short NumeroChamp,
char* ValeurChamp,
size_t* TailleMax);
/* Lecture d'un champ vers un fichier. */
extern unsigned short API_ENTRY
SGD_LireChampFichier (unsigned short NumeroSession,
unsigned short IdGroupe,
unsigned short OccurrenceGroupe,
unsigned short NumeroChamp,
const char* NomFichier);
/* Activation de la trace. */
extern unsigned short API_ENTRY
SGD_InitTrace (const char* NomFichier,
const char* ModeOuverture,
unsigned short Module,
unsigned char Niveau);
/*Initialisation de SGD*/
unsigned short API_ENTRY SGD_Init(const char *fichierSesam);
/* Transmission de la zone d'entrée. */
extern unsigned short API_ENTRY SGD_LireZoneIn(unsigned short NumeroSession,
void** ZDonneesEntree,
size_t* TailleDonneesEntree);
/* Transmission de la zone de sortie. */
typedef void (API_ENTRY *LibererZoneMem) (void* Zone);
extern unsigned short API_ENTRY SGD_EcrireZoneOut(unsigned short NumeroSession,
void* ZDonneesSortie,
size_t TailleDonneesSortie,
LibererZoneMem Fonction);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,176 +0,0 @@
/*
* -------------------------------------------------------------------
* (c) 2001-2003 GIE SESAM-VITALE
*
* PROJET : Services Reglementation et Tarification
*
* FICHIER : srt.h (v5)
*
* Declaration des prototypes des fonctions SRT
* -------------------------------------------------------------------
*/
#ifndef __SRT_H__
#define __SRT_H__
#ifdef __cplusplus
extern "C" {
#endif
/*
* Inclusions
*/
#include <stddef.h>
/* Inclure le fichier de d<>clarations sp<73>cifiques syst<73>me : win32def.h, macosdef.h, unixdef.h, etc. */
/*
* Declarations des fonctions publiques "standards"
*/
/* Recherche de codes CCAM par mot cle. */
typedef unsigned short (API_ENTRY FARPTR SRT_RechercherParMotCle)
(const char* MotCle,
unsigned long CadreRecherche,
void** ZDonneesSortie,
size_t* TailleDonneesSortie);
/* Recherche de codes CCAM par filtre. */
typedef unsigned short (API_ENTRY FARPTR SRT_RechercherParFiltre)
(const char* Filtre,
void** ZDonneesSortie,
size_t* TailleDonneesSortie);
/* Consultation de donnees CCAM. */
typedef unsigned short (API_ENTRY FARPTR SRT_ConsulterDonnee)
(const char* Identifiant,
const char* DateReference,
void* ZDonneesEntree,
size_t TailleDonneesEntree,
void** ZDonneesSortie,
size_t* TailleDonneesSortie);
/* Modification d'un champ mono-occurrent. */
typedef unsigned short (API_ENTRY FARPTR SRT_ModifierDonnee)
(const char* Identifiant,
const char* DateEffet,
void* ZDonneesEntree,
size_t TailleDonneesEntree);
/* Annulation d'une modification */
typedef unsigned short (API_ENTRY FARPTR SRT_AnnulerModification)
(const char* Identifiant,
void* ZDonneesEntree,
size_t TailleDonneesEntree);
/* Controle de la validite d'une ou plusieurs donnees. */
typedef unsigned short (API_ENTRY FARPTR SRT_ControlerDonnees)
(const char* Identifiant,
const char* DateReference,
void* ZDonneesEntree,
size_t TailleDonneesEntree,
unsigned char* Resultat);
/* Regle de gestion ou de tarification. */
typedef unsigned short (API_ENTRY FARPTR SRT_AppliquerRegle)
(const char* Identifiant,
void* ZDonneesEntree,
size_t TailleDonneesEntree,
void** ZDonneesSortie,
size_t* TailleDonneesSortie);
/* Controle complet. */
typedef unsigned short (API_ENTRY FARPTR SRT_ControleComplet)
(void* ZDonneesEntree,
size_t TailleDonneesEntree,
void** ZDonneesSortie,
size_t* TailleDonneesSortie);
/* Chargement du referentiel. */
typedef unsigned short (API_ENTRY FARPTR SRT_InitLIB2)(const char* SesamIni);
/* Dechargement du referentiel. */
typedef unsigned short (API_ENTRY FARPTR SRT_TermLIB)(void);
/* Sauvegarde des modifications. */
typedef unsigned short (API_ENTRY FARPTR SRT_SauvegarderReferentiel)(const char* Commentaire);
/* Version du referentiel. */
typedef unsigned short (API_ENTRY FARPTR SRT_LireVersion)
(void** ZDonneesSortie,
size_t* TailleDonneesSortie);
/* Activation de la trace. */
typedef unsigned short (API_ENTRY FARPTR SRT_InitTrace)
(const char* pathConf,
const char* ModeOuverture,
unsigned short Module,
unsigned char Niveau);
/* Allocation d'une zone memoire. */
typedef unsigned short (API_ENTRY FARPTR SRT_AllouerZoneMem)
(void** Zone,
size_t Taille);
/* Allocation d'une zone memoire. */
typedef void (API_ENTRY FARPTR SRT_LibererZoneMem) (void* Zone);
/*
* Declarations des fonctions publiques "simplifiees"
*/
/* Recherche de codes CCAM par mot cle. */
typedef unsigned short (API_ENTRY FARPTR SRT_RechercherParMotCle_S)
(const char* MotCle,
unsigned long CadreRecherche,
unsigned short NumeroSession);
/* Recherche de codes CCAM par filtre. */
typedef unsigned short (API_ENTRY FARPTR SRT_RechercherParFiltre_S)
(const char* Filtre,
unsigned short NumeroSession);
/* Consultation de donnees CCAM. */
typedef unsigned short (API_ENTRY FARPTR SRT_ConsulterDonnee_S)
(const char* Identifiant,
const char* DateReference,
unsigned short NumeroSession);
/* Modification d'un champ mono-occurrent. */
typedef unsigned short (API_ENTRY FARPTR SRT_ModifierDonnee_S)
(const char* Identifiant,
const char* DateEffet,
unsigned short NumeroSession);
/* Annulation des modifications d'une donnee. */
typedef unsigned short (API_ENTRY FARPTR SRT_AnnulerModification_S)
(const char* Identifiant,
unsigned short NumeroSession);
/* Controle de la validite d'une ou plusieurs donnees. */
typedef unsigned short (API_ENTRY FARPTR SRT_ControlerDonnees_S)
(const char* Identifiant,
const char* DateReference,
unsigned short NumeroSession,
unsigned char* Resultat);
/* Regle de gestion ou de tarification. */
typedef unsigned short (API_ENTRY FARPTR SRT_AppliquerRegle_S)
(const char* Identifiant,
unsigned short NumeroSession);
/* Controle complet. */
typedef unsigned short (API_ENTRY FARPTR SRT_ControleComplet_S)
(unsigned short NumeroSession);
/* Version du referentiel. */
typedef unsigned short (API_ENTRY FARPTR SRT_LireVersion_S)
(unsigned short NumeroSession);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,327 +0,0 @@
/*
* -------------------------------------------------------------------
* (c) 2001-2003 GIE SESAM-VITALE
*
* PROJET : Services SESAM Vitale
*
* FICHIER : ssv.h
*
* Declaration des prototypes des fonctions SSV
* -------------------------------------------------------------------
*/
#ifndef __SSV_H__
#define __SSV_H__
#ifdef __cplusplus
extern "C" {
#endif
/*
* Inclusions
*/
#include <stddef.h>
/* Inclure le fichier de d<>clarations sp<73>cifiques syst<73>me :
win32def.h, macosdef.h, aixdef.h, etc. */
/****** FONCTIONS STANDARDS *********/
typedef unsigned short (API_ENTRY FARPTR SSV_TraduireARL)
(short NbZDataIn,
void FARPTR FARPTR TZDataIn,
size_t FARPTR TTailleZoneIn,
void FARPTR FARPTR pZDataOut,
size_t FARPTR pTailleZoneOut);
typedef unsigned short (API_ENTRY FARPTR SSV_LireCartePS)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
void FARPTR FARPTR pZDataOut,
size_t FARPTR pTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_LireConfig)
(void FARPTR FARPTR pZDataOut,
size_t FARPTR psTailleDataOut);
typedef unsigned short (API_ENTRY FARPTR SSV_FormaterFactures)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
char cFactureACreer,
char cModeSecur,
void FARPTR pZDataIn,
size_t TailleDataIn,
void FARPTR FARPTR pZDataOut,
size_t FARPTR pTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_FormaterLot)
( const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
short NBZDataIn,
void FARPTR FARPTR TZDataIn,
size_t FARPTR TTailleZoneIn,
short FARPTR pNbZDataOut,
void FARPTR FARPTR TZDataOut,
size_t FARPTR TTailleZoneOut);
typedef unsigned short (API_ENTRY FARPTR SSV_FormaterFichier)
(void FARPTR pZDataIn,size_t TailleDataIn,
void FARPTR FARPTR pZDataOut,size_t FARPTR pTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_InitTrace)
(char FARPTR pathConf, char FARPTR ModeOuverture,
unsigned short Module, unsigned char Niveau);
typedef unsigned short (API_ENTRY FARPTR SSV_AllouerZoneMem)
(void FARPTR FARPTR pZDataIn,
size_t taille);
typedef void (API_ENTRY FARPTR SSV_LibererZoneMem)
(void FARPTR pZone);
typedef unsigned short (API_ENTRY FARPTR SSV_MajDateLecteur)
(const char FARPTR pcNomRessourceLecteur,
const char FARPTR pcDateHeure);
typedef unsigned short (API_ENTRY FARPTR SSV_LireDateLecteur)
(const char FARPTR pcNomRessourceLecteur,
char FARPTR pcDateHeure);
typedef unsigned short (API_ENTRY FARPTR SSV_LireDroitsVitale)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR DateConsultation,
void FARPTR FARPTR pZDataOut,
size_t FARPTR pTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_IdentifierTLA)
(const char FARPTR pcNomRessourceLecteur,
const char FARPTR NumVersionCDC,
void FARPTR FARPTR pZDataOut,
size_t FARPTR tailleDataOut);
typedef unsigned short (API_ENTRY FARPTR SSV_DechargerFacturesPdT)
( const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR pcNumFact,
short sNbZDataIn,
void FARPTR FARPTR pvTZDataIn,
size_t FARPTR psTTailleDataIn,
short FARPTR pNbZDataOut,
void FARPTR FARPTR TZDataOut,
size_t FARPTR TTailleZoneOut);
typedef unsigned short (API_ENTRY FARPTR SSV_DechargerFSETLA)
( const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR pcNumFact,
short FARPTR pNbZDataOut,
void FARPTR FARPTR TZDataOut,
size_t FARPTR TTailleZoneOut);
typedef unsigned short (API_ENTRY FARPTR SSV_DechargerFSETLANC)
( const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR pcNumFact,
short FARPTR pNbZDataOut,
void FARPTR FARPTR TZDataOut,
size_t FARPTR TTailleZoneOut);
typedef unsigned short (API_ENTRY FARPTR SSV_EffacerTLA)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR cNumFacturation,
const char FARPTR cTypeDonnee);
typedef unsigned short (API_ENTRY FARPTR SSV_ChargerFacturesPdT)
(const char FARPTR pcNomRessourceLecteur,
const char FARPTR pcNumFacturation,
short sNbZDataIn,
void FARPTR FARPTR pvTZDataIn,
size_t FARPTR psTTailleDataIn,
short FARPTR pNbZDataOut,
void FARPTR FARPTR TZDataOut,
size_t FARPTR TTailleZoneOut);
typedef unsigned short (API_ENTRY FARPTR SSV_ChargerAppli)
(const char FARPTR pcNomRessourceLecteur,
short sNbZDataIn,
void FARPTR FARPTR pvTZDataIn,
size_t FARPTR psTTailleDataIn);
typedef unsigned short (API_ENTRY FARPTR SSV_ChargerDonneesTLA)
(const char FARPTR pcNomRessourceLecteur,
short sNbZDataIn,
void FARPTR FARPTR pvTZDataIn,
size_t FARPTR psTTailleDataIn);
typedef unsigned short (API_ENTRY FARPTR SSV_DechargerBeneficiaires)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR cNumFacturation,
short FARPTR sNbZDataOut,
void FARPTR FARPTR pTZDataOut,
size_t FARPTR sTTailleDataOut);
typedef unsigned short (API_ENTRY FARPTR SSV_TraduireFSE)
(void FARPTR pZDataIn,
size_t TailleDataIn,
void FARPTR FARPTR pZDataOut,
size_t FARPTR pTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_SecuriserFacture)
(const char FARPTR pcNomRessourcePS,
const char FARPTR pcNomRessourceLecteur,
const char FARPTR pcCodePorteurPS,
char cNologSituation,
const char FARPTR pcNumFact,
void FARPTR pvDataIn,
size_t szTailleDataIn ,
void FARPTR FARPTR pvDataOut,
size_t FARPTR pszTailleDataOut);
typedef unsigned short (API_ENTRY FARPTR SSV_InitLIB2) (const char FARPTR pcFichierSesam);
typedef unsigned short (API_ENTRY FARPTR SSV_TermLIB)();
/****** FONCTIONS SIMPLIFIEES *********/
typedef unsigned short (API_ENTRY FARPTR SIS_TraduireARL)
(unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_LireCartePS)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_LireConfig)
(unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_FormaterFactures)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
char cFacturesACreer,
char ModeSecur,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_FormaterLot)
( const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_FormaterFichier)
(unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_InitTrace)
(char FARPTR NomFichier, char FARPTR ModeOuverture,
unsigned short Module, unsigned char Niveau);
typedef unsigned short (API_ENTRY FARPTR SIS_MajDateLecteur)
(const char FARPTR pcNomRessourceLecteur,
const char FARPTR pcDateHeure);
typedef unsigned short (API_ENTRY FARPTR SIS_LireDateLecteur)
(const char FARPTR pcNomRessourceLecteur,
char FARPTR pcDateHeure);
typedef unsigned short (API_ENTRY FARPTR SIS_LireDroitsVitale)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR DateConsultation,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_IdentifierTLA)
(const char FARPTR pcNomRessourceLecteur,
const char FARPTR NumVersionCDC,
unsigned short numeroSession );
typedef unsigned short (API_ENTRY FARPTR SIS_DechargerFacturesPdT)
( const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR pcNumFact,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_DechargerFSETLA)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR pcNumFact,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_DechargerFSETLANC)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR pcNumFact,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_EffacerTLA)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR cNumFacturation,
const char FARPTR cTypeDonnee);
typedef unsigned short (API_ENTRY FARPTR SIS_ChargerFacturesPdT)
(const char FARPTR pcNomRessourceLecteur,
const char FARPTR pcNumFacturation,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_ChargerAppli)
(const char FARPTR pcNomRessourceLecteur,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_ChargerDonneesTLA)
(const char FARPTR pcNomRessourceLecteur,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_DechargerBeneficiaires)
( const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR cNumFacturation,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_TraduireFSE)
(unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_SecuriserFacture)
( const char FARPTR pcNomRessourcePS,
const char FARPTR pcNomRessourceLecteur,
const char FARPTR pcCodePorteurPS,
char cNologSituation,
const char FARPTR pcNumFact,
unsigned short numeroSession);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,412 +0,0 @@
/*
* -------------------------------------------------------------------
* (c) 2001-2003 GIE SESAM-VITALE
*
* PROJET : Services SESAM Vitale
*
* FICHIER : ssv.h
*
* Declaration des prototypes des fonctions SSV
* -------------------------------------------------------------------
*/
#ifndef __SSV_H__
#define __SSV_H__
#ifdef __cplusplus
extern "C" {
#endif
/*
* Inclusions
*/
#include <stddef.h>
/* Inclure le fichier de d<>clarations sp<73>cifiques syst<73>me :
win32def.h, macosdef.h, aixdef.h, etc. */
/****** FONCTIONS STANDARDS *********/
typedef unsigned short (API_ENTRY FARPTR SSV_TraduireARL)
(short NbZDataIn,
void FARPTR FARPTR TZDataIn,
size_t FARPTR TTailleZoneIn,
void FARPTR FARPTR pZDataOut,
size_t FARPTR pTailleZoneOut);
typedef unsigned short (API_ENTRY FARPTR SSV_LireCartePS)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
void FARPTR FARPTR pZDataOut,
size_t FARPTR pTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_LireConfig)
(void FARPTR FARPTR pZDataOut,
size_t FARPTR psTailleDataOut);
typedef unsigned short (API_ENTRY FARPTR SSV_FormaterFactures)
(char cFactureACreer,
char cModeSecur,
char cTypeFlux,
void FARPTR pZDataIn,
size_t TailleDataIn,
void FARPTR FARPTR pZDataOut,
size_t FARPTR pTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_ChiffrerFacture)
(void * pZDataIn,
size_t TailleDataIn,
void * * pZDataOut,
size_t * pTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_SignerFactureVitale)
(const char * pcNomRessourceVitale,
void * pZDataIn,
size_t szTailleDataIn,
void * * pZDataOut,
size_t * pszTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_CalculerHashFactureAssure)
(const char * pcNumSerie,
void * pZDataIn,
size_t szTailleDataIn,
void * * pZDataOut,
size_t * pszTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_AjouterSignatureAssureDansFacture)
(void * pZDataIn,
size_t szTailleDataIn,
void * * pZDataOut,
size_t * pszTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_SignerFactureCPS)
(const char * pcNomRessourcePS,
const char * pcNomRessourceLecteur,
const char * pcCodePorteurPS,
char cNologSituation,
void * pZDataIn,
size_t szTailleDataIn,
void * * pZDataOut,
size_t * pszTailleZone);
typedef unsigned short (API_ENTRY SSV_CalculerHashFacturePS)
(const char * pcNumSerieCPS,
void * pZDataIn,
size_t usTailleDataIn,
void * * pZDataOut,
size_t * pusTailleZone);
typedef unsigned short (API_ENTRY SSV_AjouterSignaturePSFacture)
(void * pZDataIn,
size_t szTailleDataIn,
void * * pZDataOut,
size_t * pszTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_SignerLotCPS)
(const char * pcNomRessourcePS,
const char * pcNomRessourceLecteur,
const char * pcCodePorteurPS,
char cNologSituation,
void * pZDataIn,
size_t szTailleDataIn,
void * * pZDataOut,
size_t * pszTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_FormaterLot)
( short NBZDataIn,
void FARPTR FARPTR TZDataIn,
size_t FARPTR TTailleZoneIn,
short FARPTR pNbZDataOut,
void FARPTR FARPTR TZDataOut,
size_t FARPTR TTailleZoneOut);
typedef unsigned short (API_ENTRY FARPTR SSV_FormaterFichier)
(void FARPTR pZDataIn,size_t TailleDataIn,
void FARPTR FARPTR pZDataOut,size_t FARPTR pTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_InitTrace)
(char FARPTR pathConf, char FARPTR ModeOuverture,
unsigned short Module, unsigned char Niveau);
typedef unsigned short (API_ENTRY FARPTR SSV_AllouerZoneMem)
(void FARPTR FARPTR pZDataIn,
size_t taille);
typedef void (API_ENTRY FARPTR SSV_LibererZoneMem)
(void FARPTR pZone);
typedef unsigned short (API_ENTRY FARPTR SSV_MajDateLecteur)
(const char FARPTR pcNomRessourceLecteur,
const char FARPTR pcDateHeure);
typedef unsigned short (API_ENTRY FARPTR SSV_LireDateLecteur)
(const char FARPTR pcNomRessourceLecteur,
char FARPTR pcDateHeure);
typedef unsigned short (API_ENTRY FARPTR SSV_LireDroitsVitale)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR DateConsultation,
void FARPTR FARPTR pZDataOut,
size_t FARPTR pTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_IdentifierTLA)
(const char FARPTR pcNomRessourceLecteur,
const char FARPTR NumVersionCDC,
void FARPTR FARPTR pZDataOut,
size_t FARPTR tailleDataOut);
typedef unsigned short (API_ENTRY FARPTR SSV_DechargerFacturesPdT)
( const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR pcNumFact,
short sNbZDataIn,
void FARPTR FARPTR pvTZDataIn,
size_t FARPTR psTTailleDataIn,
short FARPTR pNbZDataOut,
void FARPTR FARPTR TZDataOut,
size_t FARPTR TTailleZoneOut);
typedef unsigned short (API_ENTRY FARPTR SSV_DechargerFSETLA)
( const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR pcNumFact,
short FARPTR pNbZDataOut,
void FARPTR FARPTR TZDataOut,
size_t FARPTR TTailleZoneOut);
typedef unsigned short (API_ENTRY FARPTR SSV_DechargerFSETLANC)
( const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR pcNumFact,
short FARPTR pNbZDataOut,
void FARPTR FARPTR TZDataOut,
size_t FARPTR TTailleZoneOut);
typedef unsigned short (API_ENTRY FARPTR SSV_EffacerTLA)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR cNumFacturation,
const char FARPTR cTypeDonnee);
typedef unsigned short (API_ENTRY FARPTR SSV_ChargerFacturesPdT)
(const char FARPTR pcNomRessourceLecteur,
const char FARPTR pcNumFacturation,
short sNbZDataIn,
void FARPTR FARPTR pvTZDataIn,
size_t FARPTR psTTailleDataIn,
short FARPTR pNbZDataOut,
void FARPTR FARPTR TZDataOut,
size_t FARPTR TTailleZoneOut);
typedef unsigned short (API_ENTRY FARPTR SSV_ChargerAppli)
(const char FARPTR pcNomRessourceLecteur,
short sNbZDataIn,
void FARPTR FARPTR pvTZDataIn,
size_t FARPTR psTTailleDataIn);
typedef unsigned short (API_ENTRY FARPTR SSV_ChargerDonneesTLA)
(const char FARPTR pcNomRessourceLecteur,
short sNbZDataIn,
void FARPTR FARPTR pvTZDataIn,
size_t FARPTR psTTailleDataIn);
typedef unsigned short (API_ENTRY FARPTR SSV_DechargerBeneficiaires)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR cNumFacturation,
short FARPTR sNbZDataOut,
void FARPTR FARPTR pTZDataOut,
size_t FARPTR sTTailleDataOut);
typedef unsigned short (API_ENTRY FARPTR SSV_TraduireFSE)
(void FARPTR pZDataIn,
size_t TailleDataIn,
void FARPTR FARPTR pZDataOut,
size_t FARPTR pTailleZone);
typedef unsigned short (API_ENTRY FARPTR SSV_SecuriserFacture)
(const char FARPTR pcNomRessourcePS,
const char FARPTR pcNomRessourceLecteur,
const char FARPTR pcCodePorteurPS,
char cNologSituation,
const char FARPTR pcNumFact,
void FARPTR pvDataIn,
size_t szTailleDataIn ,
void FARPTR FARPTR pvDataOut,
size_t FARPTR pszTailleDataOut);
typedef unsigned short (API_ENTRY FARPTR SSV_InitLIB2) (const char FARPTR pcFichierSesam);
typedef unsigned short (API_ENTRY FARPTR SSV_TermLIB)();
/****** FONCTIONS SIMPLIFIEES *********/
typedef unsigned short (API_ENTRY FARPTR SIS_TraduireARL)
(unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_LireCartePS)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_LireConfig)
(unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_FormaterFactures)
(char cFacturesACreer,
char ModeSecur,
char cTypeFlux,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_ChiffrerFacture)
(unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_SignerFactureVitale)
(const char * pcNomRessourceVitale,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_CalculerHashFactureAssure)
(const char * pcNumSerie,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_AjouterSignatureAssureDansFacture)
(unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_SignerFactureCPS)
(const char * pcNomRessourcePS,
const char * pcNomRessourceLecteur,
const char * pcCodePorteurPS,
char cNologSituation,
unsigned short numeroSession);
typedef unsigned short (SIS_CalculerHashFacturePS)
(const char * pcNumSerieCPS,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY SIS_AjouterSignaturePSFacture)
(unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_SignerLotCPS)
(const char * pcNomRessourcePS,
const char * pcNomRessourceLecteur,
const char * pcCodePorteurPS,
char cNologSituation,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_FormaterLot)
(unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_FormaterFichier)
(unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_InitTrace)
(char FARPTR NomFichier, char FARPTR ModeOuverture,
unsigned short Module, unsigned char Niveau);
typedef unsigned short (API_ENTRY FARPTR SIS_MajDateLecteur)
(const char FARPTR pcNomRessourceLecteur,
const char FARPTR pcDateHeure);
typedef unsigned short (API_ENTRY FARPTR SIS_LireDateLecteur)
(const char FARPTR pcNomRessourceLecteur,
char FARPTR pcDateHeure);
typedef unsigned short (API_ENTRY FARPTR SIS_LireDroitsVitale)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR DateConsultation,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_IdentifierTLA)
(const char FARPTR pcNomRessourceLecteur,
const char FARPTR NumVersionCDC,
unsigned short numeroSession );
typedef unsigned short (API_ENTRY FARPTR SIS_DechargerFacturesPdT)
( const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR pcNumFact,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_DechargerFSETLA)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR pcNumFact,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_DechargerFSETLANC)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR pcNumFact,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_EffacerTLA)
(const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR cNumFacturation,
const char FARPTR cTypeDonnee);
typedef unsigned short (API_ENTRY FARPTR SIS_ChargerFacturesPdT)
(const char FARPTR pcNomRessourceLecteur,
const char FARPTR pcNumFacturation,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_ChargerAppli)
(const char FARPTR pcNomRessourceLecteur,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_ChargerDonneesTLA)
(const char FARPTR pcNomRessourceLecteur,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_DechargerBeneficiaires)
( const char FARPTR NomRessourcePS,
const char FARPTR NomRessourceLecteur,
const char FARPTR CodePorteurPS,
const char FARPTR cNumFacturation,
unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_TraduireFSE)
(unsigned short numeroSession);
typedef unsigned short (API_ENTRY FARPTR SIS_SecuriserFacture)
( const char FARPTR pcNomRessourcePS,
const char FARPTR pcNomRessourceLecteur,
const char FARPTR pcCodePorteurPS,
char cNologSituation,
const char FARPTR pcNumFact,
unsigned short numeroSession);
/* inclusion temporaire dans ssv.h pour ne pas a avoir <20> relivrer Sedica (pas d'incidence sur le code) -> <20> inclure dans sedica.h ou commun.h*/
/* Chaine discriminante d un nom de ressource TL PCSC */
#define TL_PCSC " TL "
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,353 +0,0 @@
/*
%-----------------------------------------------------------------------------
% PROJET : STS INTERFACE
%
% MODULE : HEADER STS INTERFACE
%
% VERSION : cf #define ci-apr<70>s
%
% FICHIER : sts.h
%
% D<>claration des prototypes des fonctions STS - INTERFACE
%-----------------------------------------------------------------------------
%
% EDS DHU - 09/04/03 - Cr<43>ation du .h
%
% EDS OCL - 06/06/03 - Defect 91 : Rectification du prototype de InitTrace()
%
% EDS OCL - 04/07/03 - Defect 115 : Nettoyage de stsitf.h (devenu sts.h)
%
%-----------------------------------------------------------------------------
*/
#ifndef __STSITF_H
#define __STSITF_H
#define __STSITF_VERSION "0103"
/* Ne pas oublier d'impacter idef.h aussi */
#ifdef __cplusplus
extern "C" {
#endif
/*
% Biblioth<74>ques ANSI ou syst<73>me
%------------------------------
*/
/*
% Fichiers h inclus
%------------------
*/
#include "sys_dep.h"
/*
% Macros et Constantes
%---------------------
*/
/* OCL - Defect 115 : Suppression du #define G_xxx ici m<>me */
/* OCL - Defect 115 : Suppression du second #ifdef _cplusplus ici m<>me */
/*********************************************************************************
************************* Fonctions r<>entrantes *********************************
*********************************************************************************/
/*
%-----------------------------------------------------------------------------
% STS_Tarification
%
% R<>le : Tarification de la part compl<70>mentaire des actes de la facture
%
% Param<61>tres d'entr<74>e :
% MotifAppel (char) : 1er appel ('P') ou Appel sur echec de
% tarification ('E').
% ZDonneesEntree (void*) : Zone d'<27>change fournie par le Progiciel
% contenant toutes les informations sur la facture
% TailleDonneesEntree (size_t) : Taille de la zone d'<27>change Zin
%
% Param<61>tres de sortie :
% ZDonneesSortie (void**) : Zone d'<27>change fournie par le module STS appel<65>
% contenant toutes les informations modifi<66>es de la facture
% en entr<74>e et de nouvelles informations.
% TailleDonneesSortie (size_t*) : Taille de la zone d'<27>change Zout
%
% Valeur retourn<72>e :
% OK si pas d'erreur
% ERR_STS_NON_INITIALISE si module STS non initialis<69>
% et les codes d'erreurs de la tarification du module STS appel<65>
%
%-----------------------------------------------------------------------------
*/
/* OCL - Defect 115 : Remplacement PTR par FARPTR */
typedef unsigned short (API_ENTRY FARPTR STS_Tarification)(char MotifAppel, void FARPTR ZDonneesEntree,
size_t TailleDonneesEntree, void FARPTR FARPTR ZDonneesSortie,
size_t FARPTR TailleDonneesSortie);
/* Fonction simplifi<66>e */
/* OCL - Defect 115 : Remplacement STS_SIM par SGD */
#ifdef SGD
typedef unsigned short (API_ENTRY FARPTR STS_Tarification_S)(char MotifAppel, unsigned short NumeroSession);
#endif
/*
%-----------------------------------------------------------------------------
% STS_Assistance
%
% R<>le : Assistance <20> la facturation.
%
% Param<61>tres d'entr<74>e :
% MotifAppel (char) : 1er appel ('P') ou Appel sur echec de
% tarification ('E').
% PorteeAppel (ushort) : 0 pour une assistance sur toute la facture.
% 1..n pour une assistance sur un acte de rang donn<6E> /zone
% ZDonneesEntree (void*) : Zone d'<27>change fournie par le Progiciel
% contenant toutes les informations sur la facture
% TailleDonneesEntree (size_t) : Taille de la zone d'<27>change Zin
%
% Param<61>tres de sortie :
% ZDonneesSortie (void**) : Zone d'<27>change fournie par le module STS appel<65>
% TailleDonneesSortie (size_t*) : Taille de la zone d'<27>change Zout
%
% Valeur retourn<72>e : (idem Tarification)
% OK si pas d'erreur
% ERR_STS_NON_INITIALISE si module STS non initialis<69>
% et les codes d'erreurs de la tarification du module STS appel<65>
%
%-----------------------------------------------------------------------------
*/
/* OCL - Defect 115 : Remplacement PTR par FARPTR */
typedef unsigned short (API_ENTRY FARPTR STS_Assistance)(char MotifAppel, unsigned short PorteeAppel,
void FARPTR ZDonneesEntree, size_t TailleDonneesEntree,
void FARPTR FARPTR ZDonneesSortie, size_t FARPTR TailleDonneesSortie);
/* Fonction simplifi<66>e */
#ifdef SGD
typedef unsigned short (API_ENTRY FARPTR STS_Assistance_S)(char MotifAppel, unsigned short PorteeAppel,
unsigned short NumeroSession);
#endif
/*
%-----------------------------------------------------------------------------
% STS_LireVersion
%
% R<>le : Lecture de la version de ce module et du fichier de ces tables externes
% dans le groupe 3780. Appeller la lecture de version de chaque module STS
% puis recopier la r<>ponse 3780 de chacun dans la zone de sortie.
%
% Param<61>tres d'entr<74>e : aucun
%
% Param<61>tres de sortie :
% ZDonneesSortie (void**) : Zone d'<27>change fournie par ce module
% contenant les versions (grp 3780) demand<6E>es.
% TailleDonneesSortie (size_t*) : Taille de la zone d'<27>change Zout
%
% Valeur retourn<72>e :
% OK si pas d'erreur
% ERR_STS_NON_INITIALISE si module STS non initialis<69>
% ERR_ZOUT si ZDonneesSortie==NULL ou TailleDonneesSortie==NULL
% ERR_ZONE_ALLOC si m<>moire insuffisante pour allouer la Zout
%
%-----------------------------------------------------------------------------
*/
/* OCL - Defect 115 : Remplacement PTR par FARPTR */
typedef unsigned short (API_ENTRY FARPTR STS_LireVersion)(void FARPTR FARPTR ZDonneesSortie, size_t FARPTR TailleDonneesSortie);
/* Fonction simplifi<66>e */
#ifdef SGD
typedef unsigned short (API_ENTRY FARPTR STS_LireVersion_S)(unsigned short NumeroSession);
#endif
/*
%-----------------------------------------------------------------------------
% STS_InitTrace
%
% R<>le : Initialisation des traces du module STS-Interface dans un fichier log.
% Cette fonction permet d'activer ou d<>sactiver (niveau 0) les
% traces. Une activation requiert un nom de fichier et un mode
% d'ouverture. Un changement de niveau peut se faire sur le m<>me
% fichier ou sur un diff<66>rent s'il est pr<70>cis<69> en entr<74>e
%
% Param<61>tres d'entr<74>e :
% NomFichier (char*) : Chemin et nom de fichier de trace
% ModeOuverture (char*) : Mode d'ouverture du fichier de trace
% "a", "w" (,"ab", "wb").
% Module (ushort) : n<> de module 0 <20> 5 (6=TOUS)
% Niveau (uchar) : Niveau de trace : 0 signifie pas de trace, 1
% signifie traces de profondeur 8 et >=2 signifie traces sans limite
% de profondeur et activation traces module STS_SI
%
% Param<61>tres de sortie : aucun
%
% Valeur retourn<72>e :
% OK si pas d'erreur
% ERR_PARAM si NomFichier/ModeOuverture incorrect quand Niveau > 0
% ERR_TRACE_FILE si erreur d'ouverture du fichier de trace
%
%-----------------------------------------------------------------------------
*/
/* OCL - Defect 91 : Rectification du prototype de InitTrace() */
/* OCL - Defect 115 : Remplacement PTR par FARPTR */
typedef unsigned short (API_ENTRY FARPTR STS_InitTrace)(const char FARPTR pathConf, const char FARPTR ModeOuverture,
unsigned short Module, unsigned char Niveau);
/*********************************************************************************
************************* Fonctions d'initialisation et de terminaison *********
*********************************************************************************/
/*
%-----------------------------------------------------------------------------
% STS_InitLIB
%
% R<>le : Initialisation du module STS-Interface : Chargement des tables externes
% et suivi de parc. Appel de l'nitialisation de chaque module STS
%
% Param<61>tres d'entr<74>e : aucun
%
% Param<61>tres de sortie : aucun
%
% Valeur retourn<72>e :
% OK si pas d'erreur
% ERR_INTERNE_ITF si erreur interne du module STS-Interface (ou STS SI)
% ERR_MEM_DISPO si plus de m<>moire disponible
% ERR_PKG_PATH_INI si le chemin d'acc<63>s au fichier binaire est
% inconnu (fichier de configuration inaccessible ou information
% manquante)
% ERR_ITF_PKG_ACCES si fichier binaire de table inaccessible
% ERR_ITF_PKG_VER si version du fichier incoh<6F>rent avec version du
% module STS-Interface (dans les deux sens)
% ERR_ITF_PKG_CRC si CRC du fichier binaire est incorrect
% ERR_ITF_PKG_FORME si format du fichier incorrect
% ERR_ITF_PKG_INCPT s'il manque une table dans le fichier binaire
% ERR_ITF_PKG_NOM si le nom du fichier est diff<66>rent du nom dans
% l'en-t<>te du fichier.
% les codes suivants ne sont pas des erreurs fatales (non bloquant)
% mais juste des avertissements
% WAR_STS_DEJA_INITIALISE si module d<>j<EFBFBD> initialis<69>
% WAR_ADM_PATH si chemin au suivi de parc non trouv<75> dans fichier
% de configuration des produits SV
% WAR_ADM_FILE si impossible de cr<63>er les fichiers de suivi de
% parc
% ET les codes de retour de chaque module STS appel<65>
%
%-----------------------------------------------------------------------------
*/
/* extern unsigned short API_ENTRY STS_InitLIB(); */
/*
%-----------------------------------------------------------------------------
% STS_InitLIB2
%
% R<>le : Initialisation du module STS-Interface : Chargement des tables externes
% et suivi de parc. Appel de l'nitialisation de chaque module STS
%
% Param<61>tres d'entr<74>e :
% NomFichierIni (char*) : Chemin et nom du fichier de configuration des
% produits SESAM Vitale du poste de travail (sesam.ini)
%
% Param<61>tres de sortie : aucun
%
% Valeur retourn<72>e :
% OK si pas d'erreur
% ERR_INTERNE_ITF si erreur interne du module STS-Interface (ou STS SI)
% ERR_MEM_DISPO si plus de m<>moire disponible
% ERR_PKG_PATH_INI si le chemin d'acc<63>s au fichier binaire est
% inconnu (fichier de configuration inaccessible ou information
% manquante)
% ERR_ITF_PKG_ACCES si fichier binaire de table inaccessible
% ERR_ITF_PKG_VER si version du fichier incoh<6F>rent avec version du
% module STS-Interface (dans les deux sens)
% ERR_ITF_PKG_CRC si CRC du fichier binaire est incorrect
% ERR_ITF_PKG_FORME si format du fichier incorrect
% ERR_ITF_PKG_INCPT s'il manque une table dans le fichier binaire
% ERR_ITF_PKG_NOM si le nom du fichier est diff<66>rent du nom dans
% l'en-t<>te du fichier.
% les codes suivants ne sont pas des erreurs fatales (non bloquant)
% mais juste des avertissements
% WAR_STS_DEJA_INITIALISE si module d<>j<EFBFBD> initialis<69>
% WAR_ADM_PATH si chemin au suivi de parc non trouv<75> dans fichier
% de configuration des produits SV
% WAR_ADM_FILE si impossible de cr<63>er les fichiers de suivi de
% parc
% ET les codes de retour de chaque module STS appel<65>
%
%-----------------------------------------------------------------------------
*/
typedef unsigned short (API_ENTRY FARPTR STS_InitLIB2)(const char FARPTR nomFichierIni);
/*
%-----------------------------------------------------------------------------
% STS_TermLIB
%
% R<>le : Terminaison du module STS-Interface : D<>chargement des tables externes.
%
% Param<61>tres d'entr<74>e : aucun
%
% Param<61>tres de sortie : aucun
%
% Valeur retourn<72>e :
% OK si pas d'erreur
% ERR_INTERNE_ITF si erreur interne du module STS-Interface (ou STS SI)
%
%-----------------------------------------------------------------------------
*/
typedef unsigned short (API_ENTRY FARPTR STS_TermLIB)(void);
/*********************************************************************************
************************* Fonctions de gestion de la m<>moire *******************
*********************************************************************************/
/*
%-----------------------------------------------------------------------------
% STS_AllouerZoneMem
%
% R<>le : Allocation d'une zone d'<27>change de sortie par STS Interface.
% Cette fonction permet la r<>allocation d'une zone d'<27>change.
% L'allocation d'une nouvelle zone d'<27>change n<>cessite un pointeur
% NULL en entr<74>e !
% Cette fonctio est <20> utiliser conjointement avec STS_LibererZoneMem
% pour faciliter le Debugage (zone allou<6F>e par l'<27>crivain)
%
% Param<61>tres d'entr<74>e :
% Taille (size_t) : Taille de la zone d'<27>change <20> allouer.
%
% Param<61>tres d'entr<74>e et de sortie :
% Zone (void**) : Zone d'<27>change pr<70>allou<6F>e en entr<74>e (ou NULL).
% Zone allou<6F>e (r<>allou<6F>e) par le module STS-Interface.
%
% Valeur retourn<72>e :
% OK si pas d'erreur
% ERR_ZOUT si Zone==NULL ou Taille==0
% ERR_ZONE_ALLOC si plus de m<>moire disponible
%
%-----------------------------------------------------------------------------
*/
/* OCL - Defect 115 : Remplacement PTR par FARPTR */
typedef unsigned short (API_ENTRY FARPTR STS_AllouerZoneMem)(void FARPTR FARPTR Zone, size_t Taille);
/*
%-----------------------------------------------------------------------------
% STS_LibererZoneMem
%
% R<>le : Lib<69>ration de la zone d'<27>change de sortie par STS Interface.
%
% Param<61>tres d'entr<74>e :
% Zone (void*) : Zone d'<27>change <20> lib<69>rer (allou<6F>e pr<70>c<EFBFBD>demment par
% le module STS-Interce par STS_AllouerZoneMem).
%
% Param<61>tres de sortie : aucun
%
% Valeur retourn<72>e : aucune
%
%-----------------------------------------------------------------------------
*/
/* OCL - Defect 115 : Remplacement PTR par FARPTR */
typedef void (API_ENTRY FARPTR STS_LibererZoneMem)(void FARPTR Zone);
#ifdef __cplusplus
}
#endif
#endif /* __STSITF_H */

View File

@ -1,189 +0,0 @@
/*---------------------------------------------------------------------------
PROJET : Couche de portabilite multi-systeme
PLATE-FORME: LINUX
MODULE : Definition des macros et des types utilises par la couche
d'abstraction systeme pour la plate-forme LINUX.
Le fichier de definition des types portable (ce fichier) doit
etre inclus avant tout autre .h de definitions d'APIS gip-cps.
Ce fichier definit tous les types et macros dependants du
systeme.
FICHIER : common\linux\src\linuxdef.h
VERSION : 1.00
DATE : 10/01/2001
AUTEUR : ALVARO ROCHA
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
Modifications: (nouvelle version, date, auteur, explication)
...
- V4.31 - AROC le 12/02/2001 :
Ajout des #define TRUE et FALSE ainsi que le typedef int BOOLEEN
-----------------------------------------------------------------------------
---------------------------------------------------------------------------*/
#ifndef __CPSCASDF_H
#define __CPSCASDF_H
/*----------------- definition des macros portables ------------------------*/
#ifndef far
#define far
#endif
#ifndef FAR
#define FAR
#endif
#ifndef PTR
#define PTR *
#endif
#ifndef PVOID
#define PVOID void PTR
#endif
#ifndef FARPTR
#define FARPTR PTR
#endif
#ifndef FPVOID
#define FPVOID void FARPTR
#endif
/* AROC 12/02/2001 debut : */
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
/* AROC 12/02/2001 fin */
/*----------------- definition des types portables ------------------------*/
#ifndef CHAR
#define CHAR char
#endif
#ifndef PCHAR
#define PCHAR CHAR PTR
#endif
#ifndef PSTRG
#define PSTRG CHAR PTR
#endif
#ifndef UCHAR
#define UCHAR unsigned char
#endif
#ifndef PUCHAR
#define PUCHAR UCHAR PTR
#endif
#ifndef INT8
#define INT8 char
#endif
#ifndef INT16
#define INT16 short
#endif
#ifndef INT32
#define INT32 long
#endif
#ifndef PINT8
#define PINT8 INT8 PTR
#endif
#ifndef PINT16
#define PINT16 INT16 PTR
#endif
#ifndef PINT32
#define PINT32 INT32 PTR
#endif
#ifndef UINT8
#define UINT8 unsigned char
#endif
#ifndef UINT16
#define UINT16 unsigned short
#endif
#ifndef UINT32
#define UINT32 unsigned long
#endif
#ifndef PUINT8
#define PUINT8 UINT8 PTR
#endif
#ifndef PUINT16
#define PUINT16 UINT16 PTR
#endif
#ifndef PUINT32
#define PUINT32 UINT32 PTR
#endif
/* 11/02/1997 : Ajout DRE pour CPSCAS */
#ifndef VOID
#define VOID void
#endif
#ifndef PSTR
#define PSTR char PTR
#endif
/* 11/02/1997 : Fin */
#ifndef WORD
#define WORD unsigned short
#endif
#ifndef DWORD
#define DWORD unsigned long
#endif
//typedef unsigned char BYTE;
#ifndef BYTE
#define BYTE unsigned char
#endif
//typedef BYTE far * LPBYTE;
#ifndef LPBYTE
#define LPBYTE BYTE far *
#endif
//typedef int BOOL;
#ifndef BOOL
#define BOOL int
#endif
#ifndef Unref
#define Unref( a) a=a
#endif
#ifndef min
#define min(a,b) ((a)>(b)?(b):(a))
#endif
#ifndef max
#define max(a,b) ((a)<(b)?(b):(a))
#endif
/* Taille maximale allou<6F>e par la fonction "malloc" */
#ifndef MAXBLOC
#define MAXBLOC 4294967295
#endif
#endif

View File

@ -1,85 +0,0 @@
/*
* -------------------------------------------------------------------
* (c) 2002 GIE SESAM-VITALE
*
* FICHIER : sys_def.h (v2)
*
* PLATE-FORME : Windows 32 bits
*
* D<>finitions d<>pendantes du syst<73>me.
* -------------------------------------------------------------------
*/
#include "linuxdef.h"
#include "stdlib.h"
#ifndef __SYS_DEF_H__
#define __SYS_DEF_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifndef API_ENTRY
#define API_ENTRY
#endif
#ifndef _MAX_PATH
#define _MAX_PATH 256
#endif
#ifndef _MAX_FNAME
#define _MAX_FNAME 160
#endif
#ifndef _MAX_DIR
#define _MAX_DIR 800
#endif
#ifndef FARPTR
#define FARPTR *
#endif
#ifndef SYS_MAX_PATH
#define SYS_MAX_PATH _MAX_PATH
#endif
#ifndef SYS_MAX_FNAME
#define SYS_MAX_FNAME _MAX_FNAME
#endif
#ifndef SYS_MAX_DIR
#define SYS_MAX_DIR _MAX_DIR
#endif
#ifndef SYS_HANDLE
#define SYS_HANDLE void *
#endif
#ifndef PTR
#define PTR *
#endif
#ifndef SYSFARPROC_
#define SYSFARPROC_
typedef unsigned short (API_ENTRY FARPTR SYSFARPROC)();
#endif
/* S<>parateur utilis<69> dans le nommage des arborescences de fichiers */
#ifndef SEPARATEUR_REPERTOIRE
#define SEPARATEUR_REPERTOIRE '/'
#endif
/* Activation des fonctions simplifi<66>es. */
#ifndef SGD
#define SGD
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,92 +0,0 @@
/*
* -------------------------------------------------------------------
* (c) 2002 GIE SESAM-VITALE
*
* FICHIER : sys_def.h (v2)
*
* PLATE-FORME : MAC OSX
*
* D<>finitions d<>pendantes du syst<73>me.
* -------------------------------------------------------------------
*/
//3/11/2004 Modification pour compilation MAC OS X
#include "osxdef.h"
#include <stdarg.h>
#include <errno.h>
#include "stdlib.h"
#ifndef __SYS_DEF_H__
#define __SYS_DEF_H__
#ifdef __cplusplus
extern "C" {
#endif
//3-11-2004 Ajout pour MAc OS X
#define FALSE 0
#define TRUE 1
//3/11/2004 Modification pour compilation MAC OS X
#ifndef API_ENTRY
#define API_ENTRY
#endif
#ifndef FARPTR
#define FARPTR *
#endif
#ifndef SYS_MAX_PATH
#define SYS_MAX_PATH _MAX_PATH
#endif
#ifndef SYS_MAX_FNAME
#define SYS_MAX_FNAME _MAX_FNAME
#endif
#ifndef SYS_MAX_DIR
#define SYS_MAX_DIR _MAX_DIR
#endif
#ifndef PTR
#define PTR *
#endif
#ifndef SYS_HANDLE
//typedef void * SYS_HANDLE;
#define SYS_HANDLE void *
#endif
#ifndef SYSFARPROC_
#define SYSFARPROC_
typedef unsigned short (API_ENTRY FARPTR SYSFARPROC)();
#endif
/* S<>parateur utilis<69> dans le nommage des arborescences de fichiers */
#ifndef SEPARATEUR_REPERTOIRE
#ifdef WIN32
#define SEPARATEUR_REPERTOIRE '\\'
#else
#define SEPARATEUR_REPERTOIRE '/'
#endif
#endif
/* Activation des fonctions simplifi<66>es. */
#ifndef SGD
#define SGD
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,150 +0,0 @@
/*---------------------------------------------------------------------------
PROJET : Couche de portabilite multi-systeme
PLATE-FORME: MAC OS X
MODULE : Definition des macros et des types utilises par la couche
d'abstraction systeme pour la plate-forme LINUX.
Le fichier de definition des types portable (ce fichier) doit
etre inclus avant tout autre .h de definitions d'APIS gip-cps.
Ce fichier definit tous les types et macros dependants du
systeme.
FICHIER : common\linux\src\linuxdef.h
VERSION : 1.00
DATE : 10/01/2001
AUTEUR : ALVARO ROCHA
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
Modifications: (nouvelle version, date, auteur, explication)
...
- V4.31 - AROC le 12/02/2001 :
Ajout des #define TRUE et FALSE ainsi que le typedef int BOOLEEN
-----------------------------------------------------------------------------
---------------------------------------------------------------------------*/
#ifndef __CPSCASDF_H
#define __CPSCASDF_H
//#ifndef __MACTYPES__
/*#include <CarbonCore/MacTypes.h>*/
//#include"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers/MacTypes.h"*/
//#endif
/*----------------- definition des macros portables ------------------------*/
/* point d'entree exporte en DLL ????????????????????????????????????????? */
#define API_ENTRY /* pour l'instant */
#define far
#define FAR
#define PTR *
#define PVOID void PTR
#ifndef FARPTR
#define FARPTR PTR
#endif
#define FPVOID void FARPTR
/* AROC 18/O4/2001 ajout pour io_comm*/
#define HCOMM unsigned int
#define PHCOMM HCOMM FARPTR
/* AROC 12/02/2001 debut : */
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
/* AROC 12/02/2001 fin */
/*----------------- definition des types portables ------------------------*/
/* AROC 12/02/2001 debut : */
/* mise en commentaire de ce define car pb avec module sts où BOOLEEN est defini en char*/
//#ifndef BOOLEEN
//typedef int BOOLEEN;
//#define BOOLEEN int
//#endif
/* AROC 12/02/2001 fin */
/* Boolean */
#define BOOL Boolean
//#define _MAX_PATH 1024
typedef char CHAR;
typedef CHAR PTR PCHAR;
typedef CHAR PTR PSTRG;
typedef unsigned char UCHAR;
typedef UCHAR PTR PUCHAR;
typedef char INT8;
typedef short INT16;
typedef long INT32;
typedef INT8 PTR PINT8;
typedef INT16 PTR PINT16;
typedef INT32 PTR PINT32;
typedef unsigned char UINT8;
typedef unsigned short UINT16;
typedef unsigned long UINT32;
typedef UINT8 PTR PUINT8;
typedef UINT16 PTR PUINT16;
typedef UINT32 PTR PUINT32;
/* 11/02/1997 : Ajout DRE pour CPSCAS */
typedef void VOID;
typedef char PTR PSTR;
/* 11/02/1997 : Fin */
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef BYTE far * LPBYTE;
#define Unref( a) a=a
#ifndef min
#define min(a,b) ((a)>(b)?(b):(a))
#endif
#ifndef max
#define max(a,b) ((a)<(b)?(b):(a))
#endif
#ifdef LITTLE_ENDIAN
#undef LITTLE_ENDIAN
#endif
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
#ifndef _MAX_PATH
#define _MAX_PATH PATH_MAX /* PATH_MAX defini dans <usr/include/sys/syslimits.h> */
#endif
/* Taille maximale allouÈe par la fonction "malloc" */
#ifndef MAXBLOC
#define MAXBLOC 0x7FFFFFFF
#endif
#endif

View File

@ -1,69 +0,0 @@
/*
* -------------------------------------------------------------------
* (c) 2002 GIE SESAM-VITALE
*
* FICHIER : sys_def.h (v2)
*
* PLATE-FORME : Windows 32 bits
*
* D<>finitions d<>pendantes du syst<73>me.
* -------------------------------------------------------------------
*/
#include <stdlib.h>
#ifndef __SYS_DEF_H__
#define __SYS_DEF_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifndef API_ENTRY
#define API_ENTRY __stdcall
#endif
#ifndef FARPTR
#define FARPTR *
#endif
#ifndef SYS_MAX_PATH
#define SYS_MAX_PATH _MAX_PATH
#endif
#ifndef SYS_MAX_FNAME
#define SYS_MAX_FNAME _MAX_FNAME
#endif
#ifndef SYS_MAX_DIR
#define SYS_MAX_DIR _MAX_DIR
#endif
typedef void * SYS_HANDLE;
#ifndef PTR
#define PTR *
#endif
typedef unsigned short (API_ENTRY FARPTR SYSFARPROC)();
/* S<>parateur utilis<69> dans le nommage des arborescences de fichiers */
#ifndef SEPARATEUR_REPERTOIRE
#define SEPARATEUR_REPERTOIRE '\\'
#endif
/* Activation des fonctions simplifi<66>es. */
#ifndef SGD
#define SGD
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,3 @@
SESAM_FSV_VERSION=1.40.14
SESAM_FSV_LIB_PATH="C:/Program Files/santesocial/fsv/${SESAM_FSV_VERSION}/lib"
SESAM_FSV_SSVLIB=ssvw64

View File

@ -0,0 +1,2 @@
SESAM_FSV_VERSION=1.40.14
SESAM_INI_PATH=${ALLUSERSPROFILE}\\santesocial\\fsv\\${SESAM_FSV_VERSION}\\conf\\sesam.ini

View File

@ -4,10 +4,8 @@ version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0"
dotenv = "0.15"
libc = "0.2"
thiserror = "1.0"
utils = { path = "../utils" }
[build-dependencies]
dotenv = "0.15"

View File

@ -1,13 +1,13 @@
extern crate dotenv;
use std::env;
use std::path::PathBuf;
use dotenv::from_path;
fn main() {
// Load the .env.build file for build-time environment variables
let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set");
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let manifest_path = PathBuf::from(manifest_dir);
from_path(manifest_path.join(".env.build")).ok();
dotenv::from_path(manifest_path.join(".env.build")).ok();
println!("cargo::rerun-if-env-changed=SESAM_FSV_LIB_PATH");
println!("cargo::rerun-if-env-changed=SESAM_FSV_SSVLIB");
@ -22,13 +22,12 @@ fn main() {
);
// Add the SESAM_FSV_LIB_PATH to the linker search path
let fsv_lib_path =
PathBuf::from(env::var("SESAM_FSV_LIB_PATH").expect("SESAM_FSV_LIB_PATH must be set"));
let fsv_lib_path = PathBuf::from(env::var("SESAM_FSV_LIB_PATH").unwrap());
println!("cargo::rustc-link-search=native={}", fsv_lib_path.display());
// Add the SESAM_FSV_LIB_PATH to the PATH environment variable
if cfg!(target_os = "windows") {
let path = env::var("PATH").unwrap_or_default();
let path = env::var("PATH").unwrap_or(String::new());
println!("cargo:rustc-env=PATH={};{}", fsv_lib_path.display(), path);
} else if cfg!(target_os = "linux") {
println!("cargo:rustc-env=LD_LIBRARY_PATH={}", fsv_lib_path.display());
@ -37,7 +36,7 @@ fn main() {
// Link the SESAM_FSV_SSVLIB dynamic library
println!(
"cargo::rustc-link-lib=dylib={}",
env::var("SESAM_FSV_SSVLIB").expect("SESAM_FSV_SSVLIB must be set")
env::var("SESAM_FSV_SSVLIB").unwrap()
);
// TODO : try `raw-dylib` instead of `dylib` on Windows to avoid the need of the `lib` headers compiled from the `def`
}

Binary file not shown.

View File

@ -0,0 +1,876 @@
use libc::{c_void, size_t};
use std::ffi::CString;
use std::ptr;
use crate::libssv::SSV_LireDroitsVitale;
use crate::ssv_memory::{decode_ssv_memory, Block};
#[derive(Debug, Default)]
pub struct CarteVitale {
donneesAssure: DonneesAssure,
serviceAMOFamille: ServiceAMOFamille,
donneesAccidentTravail: DonneesAccidentTravail,
donneesBeneficiaire: Vec<DonneesBeneficiaire>,
}
// 1. CB = Caractères Binaires »
// 2. CE = Caractères « Etendus » (ISO 8859-1)
// 3. CA = Caractères Alphanumériques (ASCII?)
// 4. CN = Caractères Numériques
#[derive(Debug, Default)]
struct DonneesAssure {
type_de_carte_vitale: char, // CA
numero_de_serie: String, // CN - 1 -> 20
date_de_fin_de_validite: String, // CN - Format AAAAMMJJ0000
donnees_administration_ruf1: char, // CN
donnees_administration_ruf2: String, // CA - 24
donnees_ruf_administration: String, // CE - 10
type_d_identification_du_porteur: char, // CA
numero_national_d_immatriculation: String, // CA - 13
cle_du_nir: String, // CA - 2
code_regime: String, // CN - 2
caisse_gestionnaire: String, // CN - 3
centre_gestionnaire: String, // CN - 4
code_gestion: String, // CA - 2
donnees_ruf_famille: String, // CE - 55
}
#[derive(Debug, Default)]
struct ServiceAMOFamille {
code_service_amo_famille: String, // CN - 2
date_de_debut_service_amo_famille: String, // CN - Format AAAAMMJJ0000
date_de_fin_service_amo_famille: String, // CN - Format AAAAMMJJ0000
}
#[derive(Debug, Default)]
struct DonneesAccidentTravail {
organisme_gestionnaire_risque_at: String, // CN - 9
code_at: char, // CA - 2
identifiant_at: String, // CN - 9
organisme_gestionnaire_at1: String, // CN - 9
code_at1: char, // CA - 2
identifiant_at1: String, // CN - 9
organisme_gestionnaire_at2: String, // CN - 9
code_at2: char, // CA - 2
identifiant_at2: String, // CN - 9
}
#[derive(Debug, Default)]
struct DonneesBeneficiaire {
nom_usuel: String, // CE - 27
nom_de_famille: String, // CE - 27
prenom: String, // CE - 27
adresse_ligne_1: String, // CE - 32
adresse_ligne_2: String, // CE - 32
adresse_ligne_3: String, // CE - 32
adresse_ligne_4: String, // CE - 32
adresse_ligne_5: String, // CE - 32
nir_certifie: String, // CA - 13
cle_du_nir_certifie: String, // CN - 2
date_de_certification_du_nir: String, // CN - Format AAAAMMJJ0000
date_de_naissance: String, // CN - Format AAAAMMJJ0000
rang_de_naissance: String, // CN - 1
qualite: String, // CN - 2
code_service_amo_beneficiaire: char, // CA - 2
date_de_debut_service_amo: String, // CN - Format AAAAMMJJ0000
date_de_fin_service_amo: String, // CN - Format AAAAMMJJ0000
donnees_ruf_amo: String, // CE - 30
periodeDroitsAMO: Vec<PeriodeDroitsAMO>,
periodeCodeCouverture: Vec<PeriodeCodeCouverture>,
donneesMutuelle: DonneesMutuelle,
donneesComplementaire: DonneesComplementaire,
donneesRUFBeneficiaireComplementaire: DonneesRUFBeneficiaireComplementaire,
}
#[derive(Debug, Default)]
struct PeriodeDroitsAMO {
date_de_debut_droits_amo: String, // CN - Format AAAAMMJJ0000
date_de_fin_droits_amo: String, // CN - Format AAAAMMJJ0000
}
#[derive(Debug, Default)]
struct PeriodeCodeCouverture {
date_de_debut_code_couverture: String, // CN - Format AAAAMMJJ0000
date_de_fin_code_couverture: String, // CN - Format AAAAMMJJ0000
code_ald: String, // CN - 1
code_situation: String, // CN - 4
}
#[derive(Debug, Default)]
struct DonneesMutuelle {
identification_mutuelle: String, // CN - 8
garanties_effectives: String, // CA - 8
indicateur_de_traitement_mutuelle: String, // CN - 2
type_de_services_associes: char, // CA - 1
services_associes_au_contrat: String, // CA - 17
code_aiguillage_sts: char, // CA - 1
periodeDroitsMutuelle: Vec<PeriodeDroitsMutuelle>,
}
#[derive(Debug, Default)]
struct PeriodeDroitsMutuelle {
date_de_debut_droits_mutuelle: String, // CN - Format AAAAMMJJ0000
date_de_fin_droits_mutuelle: String, // CN - Format AAAAMMJJ0000
}
#[derive(Debug, Default)]
struct DonneesComplementaire {
numero_complementaire_b2: String, // CA - 10
numero_complementaire_edi: String, // CA - 19
numero_adherent_amc: String, // CA - 8
indicateur_de_traitement_amc: String, // CN - 2
date_de_debut_validite_amc: String, // CN - Format AAAAMMJJ0000
date_de_fin_validite_amc: String, // CN - Format AAAAMMJJ0000
code_routage_flux_amc: String, // CA - 2
identifiant_hote: String, // CA - 3
nom_de_domaine_amc: String, // CE - 20
code_aiguillage_sts: char, // CA - 1
type_de_services_associes: char, // CA - 1
services_associes_au_contrat: String, // CE - 17
}
#[derive(Debug, Default)]
struct DonneesRUFBeneficiaireComplementaire {
donnees_ruf_beneficiaire_complementaire: String, // CE - 115
}
pub fn LireDroitsVitale(
lecteurPS: &str,
lecteurVitale: &str,
codePorteurPS: &str,
dateConsultation: &str,
) -> Result<CarteVitale, String> {
let resource_ps = CString::new(lecteurPS).expect("CString::new failed");
let resource_vitale = CString::new(lecteurVitale).expect("CString::new failed");
let card_number = CString::new(codePorteurPS).expect("CString::new failed");
let date_consultation = CString::new(dateConsultation).expect("CString::new failed");
let mut buffer: *mut c_void = ptr::null_mut();
let mut size: size_t = 0;
let mut hex_values: &[u8] = &[];
unsafe {
let result = SSV_LireDroitsVitale(
resource_ps.as_ptr(),
resource_vitale.as_ptr(),
card_number.as_ptr(),
date_consultation.as_ptr(),
&mut buffer,
&mut size,
);
println!("SSV_LireDroitsVitale result: {}", result);
if !buffer.is_null() {
hex_values = std::slice::from_raw_parts(buffer as *const u8, size);
}
}
let groups = decode_ssv_memory(hex_values, hex_values.len());
let OUT = decode_carte_vitale(groups);
unsafe {
if !buffer.is_null() {
libc::free(buffer); // ??? si liberer avant decode_ssv_memory et decode_carte_vitale alors hex_values n'est plus correct ???
}
}
OUT
}
fn decode_carte_vitale(groups: Vec<Block>) -> Result<CarteVitale, String> {
let mut cartevitale = CarteVitale::default();
for group in groups {
for field in group.content {
match (group.id, field.id) {
(104, 1) => {
cartevitale
.donneesBeneficiaire
.push(DonneesBeneficiaire::default());
}
(105, 1) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.periodeDroitsAMO
.push(PeriodeDroitsAMO::default());
}
(106, 1) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.periodeCodeCouverture
.push(PeriodeCodeCouverture::default());
}
(108, 1) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesMutuelle
.periodeDroitsMutuelle
.push(PeriodeDroitsMutuelle::default());
}
_ => {}
}
if field.content.len() > 0 {
match (group.id, field.id) {
(101, 1) => {
let byte = field.content[0];
cartevitale.donneesAssure.type_de_carte_vitale = byte as char;
}
(101, 2) => {
cartevitale.donneesAssure.numero_de_serie = //bytes_to_decimal_string(&field.content);
String::from_utf8_lossy(field.content).to_string();
}
(101, 3) => {
cartevitale.donneesAssure.date_de_fin_de_validite =
String::from_utf8_lossy(field.content).to_string();
}
(101, 4) => {
println!("101.4 field.size: {:#?}", field.size);
let byte = field.content[0];
cartevitale.donneesAssure.donnees_administration_ruf1 = byte as char;
}
(101, 5) => {
cartevitale.donneesAssure.donnees_administration_ruf2 =
String::from_utf8_lossy(field.content).to_string();
}
(101, 6) => {
cartevitale.donneesAssure.donnees_ruf_administration =
String::from_utf8_lossy(field.content).to_string();
}
(101, 7) => {
let byte = field.content[0];
cartevitale.donneesAssure.type_d_identification_du_porteur = byte as char;
}
(101, 8) => {
cartevitale.donneesAssure.numero_national_d_immatriculation =
String::from_utf8_lossy(field.content).to_string();
}
(101, 9) => {
cartevitale.donneesAssure.cle_du_nir =
String::from_utf8_lossy(field.content).to_string();
}
(101, 10) => {
cartevitale.donneesAssure.code_regime =
String::from_utf8_lossy(field.content).to_string();
}
(101, 11) => {
cartevitale.donneesAssure.caisse_gestionnaire =
String::from_utf8_lossy(field.content).to_string();
}
(101, 12) => {
cartevitale.donneesAssure.centre_gestionnaire =
String::from_utf8_lossy(field.content).to_string();
}
(101, 13) => {
cartevitale.donneesAssure.code_gestion =
String::from_utf8_lossy(field.content).to_string();
}
(101, 14) => {
cartevitale.donneesAssure.donnees_ruf_famille =
String::from_utf8_lossy(field.content).to_string();
}
(102, 1) => {
cartevitale.serviceAMOFamille.code_service_amo_famille =
String::from_utf8_lossy(field.content).to_string();
}
(102, 2) => {
cartevitale
.serviceAMOFamille
.date_de_debut_service_amo_famille =
String::from_utf8_lossy(field.content).to_string();
}
(102, 3) => {
cartevitale
.serviceAMOFamille
.date_de_fin_service_amo_famille =
String::from_utf8_lossy(field.content).to_string();
}
(103, 1) => {
cartevitale
.donneesAccidentTravail
.organisme_gestionnaire_risque_at =
String::from_utf8_lossy(field.content).to_string();
}
(103, 2) => {
let byte = field.content[0];
cartevitale.donneesAccidentTravail.code_at = byte as char;
}
(103, 3) => {
cartevitale.donneesAccidentTravail.identifiant_at =
String::from_utf8_lossy(field.content).to_string();
}
(103, 4) => {
cartevitale
.donneesAccidentTravail
.organisme_gestionnaire_at1 =
String::from_utf8_lossy(field.content).to_string();
}
(103, 5) => {
let byte = field.content[0];
cartevitale.donneesAccidentTravail.code_at1 = byte as char;
}
(103, 6) => {
cartevitale.donneesAccidentTravail.identifiant_at1 =
String::from_utf8_lossy(field.content).to_string();
}
(103, 7) => {
cartevitale
.donneesAccidentTravail
.organisme_gestionnaire_at2 =
String::from_utf8_lossy(field.content).to_string();
}
(103, 8) => {
let byte = field.content[0];
cartevitale.donneesAccidentTravail.code_at2 = byte as char;
}
(103, 9) => {
cartevitale.donneesAccidentTravail.identifiant_at2 =
String::from_utf8_lossy(field.content).to_string();
}
(104, 1) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.nom_usuel = String::from_utf8_lossy(field.content).to_string();
}
(104, 2) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.nom_de_famille = String::from_utf8_lossy(field.content).to_string();
}
(104, 3) => {
cartevitale.donneesBeneficiaire.last_mut().unwrap().prenom =
String::from_utf8_lossy(field.content).to_string();
}
(104, 4) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.adresse_ligne_1 = String::from_utf8_lossy(field.content).to_string();
}
(104, 5) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.adresse_ligne_2 = String::from_utf8_lossy(field.content).to_string();
}
(104, 6) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.adresse_ligne_3 = String::from_utf8_lossy(field.content).to_string();
}
(104, 7) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.adresse_ligne_4 = String::from_utf8_lossy(field.content).to_string();
}
(104, 8) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.adresse_ligne_5 = String::from_utf8_lossy(field.content).to_string();
}
(104, 9) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.nir_certifie = String::from_utf8_lossy(field.content).to_string();
}
(104, 10) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.cle_du_nir_certifie =
String::from_utf8_lossy(field.content).to_string();
}
(104, 11) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.date_de_certification_du_nir =
String::from_utf8_lossy(field.content).to_string();
}
(104, 12) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.date_de_naissance = String::from_utf8_lossy(field.content).to_string();
}
(104, 13) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.rang_de_naissance = String::from_utf8_lossy(field.content).to_string();
}
(104, 14) => {
cartevitale.donneesBeneficiaire.last_mut().unwrap().qualite =
String::from_utf8_lossy(field.content).to_string();
}
(104, 15) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.code_service_amo_beneficiaire = field.content[0] as char;
}
(104, 16) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.date_de_debut_service_amo =
String::from_utf8_lossy(field.content).to_string();
}
(104, 17) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.date_de_fin_service_amo =
String::from_utf8_lossy(field.content).to_string();
}
(104, 18) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donnees_ruf_amo = String::from_utf8_lossy(field.content).to_string();
}
(105, 1) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.periodeDroitsAMO
.last_mut()
.unwrap()
.date_de_debut_droits_amo =
String::from_utf8_lossy(field.content).to_string();
}
(105, 2) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.periodeDroitsAMO
.last_mut()
.unwrap()
.date_de_fin_droits_amo =
String::from_utf8_lossy(field.content).to_string();
}
(106, 1) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.periodeCodeCouverture
.last_mut()
.unwrap()
.date_de_debut_code_couverture =
String::from_utf8_lossy(field.content).to_string();
}
(106, 2) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.periodeCodeCouverture
.last_mut()
.unwrap()
.date_de_fin_code_couverture =
String::from_utf8_lossy(field.content).to_string();
}
(106, 3) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.periodeCodeCouverture
.last_mut()
.unwrap()
.code_ald = String::from_utf8_lossy(field.content).to_string();
}
(106, 4) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.periodeCodeCouverture
.last_mut()
.unwrap()
.code_situation = String::from_utf8_lossy(field.content).to_string();
}
(107, 1) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesMutuelle
.identification_mutuelle =
String::from_utf8_lossy(field.content).to_string();
}
(107, 2) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesMutuelle
.garanties_effectives =
String::from_utf8_lossy(field.content).to_string();
}
(107, 3) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesMutuelle
.indicateur_de_traitement_mutuelle =
String::from_utf8_lossy(field.content).to_string();
}
(107, 4) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesMutuelle
.type_de_services_associes = field.content[0] as char;
}
(107, 5) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesMutuelle
.services_associes_au_contrat =
String::from_utf8_lossy(field.content).to_string();
}
(107, 6) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesMutuelle
.code_aiguillage_sts = field.content[0] as char;
}
(108, 1) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesMutuelle
.periodeDroitsMutuelle
.last_mut()
.unwrap()
.date_de_debut_droits_mutuelle =
String::from_utf8_lossy(field.content).to_string();
}
(108, 2) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesMutuelle
.periodeDroitsMutuelle
.last_mut()
.unwrap()
.date_de_fin_droits_mutuelle =
String::from_utf8_lossy(field.content).to_string();
}
(109, 1) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesComplementaire
.numero_complementaire_b2 =
String::from_utf8_lossy(field.content).to_string();
}
(109, 2) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesComplementaire
.numero_complementaire_edi =
String::from_utf8_lossy(field.content).to_string();
}
(109, 3) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesComplementaire
.numero_adherent_amc =
String::from_utf8_lossy(field.content).to_string();
}
(109, 4) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesComplementaire
.indicateur_de_traitement_amc =
String::from_utf8_lossy(field.content).to_string();
}
(109, 5) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesComplementaire
.date_de_debut_validite_amc =
String::from_utf8_lossy(field.content).to_string();
}
(109, 6) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesComplementaire
.date_de_fin_validite_amc =
String::from_utf8_lossy(field.content).to_string();
}
(109, 7) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesComplementaire
.code_routage_flux_amc =
String::from_utf8_lossy(field.content).to_string();
}
(109, 8) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesComplementaire
.identifiant_hote = String::from_utf8_lossy(field.content).to_string();
}
(109, 9) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesComplementaire
.nom_de_domaine_amc =
String::from_utf8_lossy(field.content).to_string();
}
(109, 10) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesComplementaire
.code_aiguillage_sts = field.content[0] as char;
}
(109, 11) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesComplementaire
.type_de_services_associes = field.content[0] as char;
}
(109, 12) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesComplementaire
.services_associes_au_contrat =
String::from_utf8_lossy(field.content).to_string();
}
(111, 1) => {
cartevitale
.donneesBeneficiaire
.last_mut()
.unwrap()
.donneesRUFBeneficiaireComplementaire
.donnees_ruf_beneficiaire_complementaire =
String::from_utf8_lossy(field.content).to_string();
}
_ => {
return Err(format!(
"Unknown (group, field) pair: ({}, {})",
group.id, field.id
))
}
}
}
}
}
Ok(cartevitale)
}
// #[cfg(test)]
// mod test_decode_carte_ps {
// use super::*;
// #[test]
// fn test_francoise_pharmacien0052419() {
// let bytes: &[u8] = &[
// 0, 1, 51, // Block 01, Content size 51
// 1, 48, // Field 01, Content size 1
// 1, 56, // Field 02, Content size 1
// 11, 57, 57, 55, 48, 48, 53, 50, 52, 49, 57, 52, // Field 03, Content size 11
// 1, 52, // Field 04, Content size 1
// 2, 50, 50, // Field 05, Content size 2
// 17, 80, 72, 65, 82, 77, 65, 67, 73, 69, 78, 48, 48, 53, 50, 52, 49,
// 57, // Field 06, Content size 17
// 9, 70, 82, 65, 78, 67, 79, 73, 83, 69, // Field 07, Content size 9
// 1, 84, // Field 08, Content size 1
// 0, 2, 83, // Block 02, Content size 83
// 1, 1, 1, 48, 1, 49, 2, 56, 54, 1, 49, 9, 48, 66, 48, 50, 50, 49, 57, 53, 56, 1, 56, 24,
// 80, 72, 65, 82, 77, 65, 67, 73, 69, 32, 68, 85, 32, 67, 69, 78, 84, 82, 69, 50, 50, 49,
// 57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53, 48, 2, 49,
// 48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
// ];
// let blocks = decode_ssv_memory(bytes, bytes.len());
// let carte_ps = decode_carte_ps(blocks).unwrap();
// assert_eq!(carte_ps.titulaire.type_de_carte_ps, "0");
// assert_eq!(carte_ps.titulaire.type_d_identification_nationale, "8");
// assert_eq!(
// carte_ps.titulaire.numero_d_identification_nationale,
// "99700524194"
// );
// assert_eq!(
// carte_ps.titulaire.cle_du_numero_d_identification_nationale,
// "4"
// );
// assert_eq!(carte_ps.titulaire.code_civilite, "22");
// assert_eq!(carte_ps.titulaire.nom_du_ps, "PHARMACIEN0052419");
// assert_eq!(carte_ps.titulaire.prenom_du_ps, "FRANCOISE");
// assert_eq!(carte_ps.titulaire.categorie_carte, 'T');
// assert_eq!(carte_ps.situations.len(), 1);
// assert_eq!(
// carte_ps.situations[0].numero_logique_de_la_situation_de_facturation_du_ps,
// 1
// );
// assert_eq!(carte_ps.situations[0].mode_d_exercice, "0");
// assert_eq!(carte_ps.situations[0].statut_d_exercice, "1");
// assert_eq!(carte_ps.situations[0].secteur_d_activite, "86");
// assert_eq!(carte_ps.situations[0].type_d_identification_structure, "1");
// assert_eq!(
// carte_ps.situations[0].numero_d_identification_structure,
// "0B0221958"
// );
// assert_eq!(
// carte_ps.situations[0].cle_du_numero_d_identification_structure,
// "8"
// );
// assert_eq!(
// carte_ps.situations[0].raison_sociale_structure,
// "PHARMACIE DU CENTRE22195"
// );
// assert_eq!(
// carte_ps.situations[0].numero_d_identification_de_facturation_du_ps,
// "00202419"
// );
// assert_eq!(
// carte_ps.situations[0].cle_du_numero_d_identification_de_facturation_du_ps,
// "8"
// );
// assert_eq!(
// carte_ps.situations[0].numero_d_identification_du_ps_remplaçant,
// ""
// );
// assert_eq!(
// carte_ps.situations[0].cle_du_numero_d_identification_du_ps_remplaçant,
// "0"
// );
// assert_eq!(carte_ps.situations[0].code_conventionnel, "1");
// assert_eq!(carte_ps.situations[0].code_specialite, "50");
// assert_eq!(carte_ps.situations[0].code_zone_tarifaire, "10");
// assert_eq!(carte_ps.situations[0].code_zone_ik, "00");
// assert_eq!(carte_ps.situations[0].code_agrement_1, "0");
// assert_eq!(carte_ps.situations[0].code_agrement_2, "0");
// assert_eq!(carte_ps.situations[0].code_agrement_3, "0");
// assert_eq!(
// carte_ps.situations[0].habilitation_à_signer_une_facture,
// "1"
// );
// assert_eq!(carte_ps.situations[0].habilitation_à_signer_un_lot, "1");
// }
// #[test]
// fn test_multiple_situations() {
// let bytes: &[u8] = &[
// 0, 1, 51, // Block 01, Content size 51
// 1, 48, 1, 56, 11, 57, 57, 55, 48, 48, 53, 50, 52, 49, 57, 52, 1, 52, 2, 50, 50, 17, 80,
// 72, 65, 82, 77, 65, 67, 73, 69, 78, 48, 48, 53, 50, 52, 49, 57, 9, 70, 82, 65, 78, 67,
// 79, 73, 83, 69, 1, 84, 0, 2, 83, // Block 02, Content size 83
// 1, 1, 1, 48, 1, 49, 2, 56, 54, 1, 49, 9, 48, 66, 48, 50, 50, 49, 57, 53, 56, 1, 56, 24,
// 80, 72, 65, 82, 77, 65, 67, 73, 69, 32, 68, 85, 32, 67, 69, 78, 84, 82, 69, 50, 50, 49,
// 57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53, 48, 2, 49,
// 48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 0, 3,
// 83, // Block 03, Content size 83
// 1, 1, 1, 48, 1, 49, 2, 56, 54, 1, 49, 9, 48, 66, 48, 50, 50, 49, 57, 53, 56, 1, 56, 24,
// 80, 72, 65, 82, 77, 65, 67, 73, 69, 32, 68, 85, 32, 67, 69, 78, 84, 82, 69, 50, 50, 49,
// 57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53, 48, 2, 49,
// 48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 0, 4,
// 83, // Block 04, Content size 83
// 1, 1, 1, 48, 1, 49, 2, 56, 54, 1, 49, 9, 48, 66, 48, 50, 50, 49, 57, 53, 56, 1, 56, 24,
// 80, 72, 65, 82, 77, 65, 67, 73, 69, 32, 68, 85, 32, 67, 69, 78, 84, 82, 69, 50, 50, 49,
// 57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53, 48, 2, 49,
// 48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
// ];
// let blocks = decode_ssv_memory(bytes, bytes.len());
// let carte_ps = decode_carte_ps(blocks).unwrap();
// assert_eq!(carte_ps.situations.len(), 3);
// assert_eq!(
// carte_ps.situations[0].raison_sociale_structure,
// "PHARMACIE DU CENTRE22195"
// );
// assert_eq!(
// carte_ps.situations[1].raison_sociale_structure,
// "PHARMACIE DU CENTRE22195"
// );
// assert_eq!(
// carte_ps.situations[2].raison_sociale_structure,
// "PHARMACIE DU CENTRE22195"
// );
// }
// #[test]
// #[should_panic]
// fn test_missing_field() {
// todo!();
// }
// #[test]
// #[should_panic]
// fn test_unknown_group_field_pair() {
// todo!();
// }
// #[test]
// #[should_panic]
// fn test_invalid_field_format() {
// todo!();
// }
// }

View File

@ -1,24 +1,9 @@
use libc::{c_void, size_t};
use std::ffi::CString;
use std::ptr;
use thiserror::Error;
use crate::libssv::{self, SSV_LireCartePS};
use crate::ssv_memory::{decode_ssv_memory, Block, SSVMemoryError};
#[derive(Error, Debug)]
pub enum CartePSError {
#[error("Unknown (group, field) pair: ({group}, {field})")]
UnknownGroupFieldPair { group: u16, field: u16 },
#[error("CString creation error: {0}")]
CString(#[from] std::ffi::NulError),
#[error("Unable to get the last situation while parsing a CartePS")]
InvalidLastSituation,
#[error(transparent)]
SSVMemory(#[from] SSVMemoryError),
#[error(transparent)]
SSVLibErrorCode(#[from] libssv::LibSSVError),
}
use crate::libssv::SSV_LireCartePS;
use crate::ssv_memory::{decode_ssv_memory, Block};
#[derive(Debug, Default)]
pub struct CartePS {
@ -67,10 +52,10 @@ struct SituationPS {
habilitation_à_signer_un_lot: String,
}
pub fn lire_carte(code_pin: &str, lecteur: &str) -> Result<CartePS, CartePSError> {
let resource_ps = CString::new(lecteur)?;
let resource_reader = CString::new("")?;
let card_number = CString::new(code_pin)?;
pub fn lire_carte(code_pin: &str, lecteur: &str) -> Result<CartePS, String> {
let resource_ps = CString::new(lecteur).expect("CString::new failed");
let resource_reader = CString::new("").expect("CString::new failed");
let card_number = CString::new(code_pin).expect("CString::new failed");
let mut buffer: *mut c_void = ptr::null_mut();
let mut size: size_t = 0;
@ -84,32 +69,17 @@ pub fn lire_carte(code_pin: &str, lecteur: &str) -> Result<CartePS, CartePSError
&mut size,
);
println!("SSV_LireCartePS result: {}", result);
if result != 0 {
return Err(libssv::LibSSVError::StandardErrorCode {
code: result,
function: "SSV_LireCartePS",
}
.into());
}
if !buffer.is_null() {
hex_values = std::slice::from_raw_parts(buffer as *const u8, size);
libc::free(buffer);
}
}
let groups =
decode_ssv_memory(hex_values, hex_values.len()).map_err(CartePSError::SSVMemory)?;
let groups = decode_ssv_memory(hex_values, hex_values.len());
decode_carte_ps(groups)
}
fn get_last_mut_situation(carte_ps: &mut CartePS) -> Result<&mut SituationPS, CartePSError> {
carte_ps
.situations
.last_mut()
.ok_or(CartePSError::InvalidLastSituation)
}
fn decode_carte_ps(groups: Vec<Block>) -> Result<CartePS, CartePSError> {
fn decode_carte_ps(groups: Vec<Block>) -> Result<CartePS, String> {
let mut carte_ps = CartePS::default();
for group in groups {
for field in group.content {
@ -148,99 +118,137 @@ fn decode_carte_ps(groups: Vec<Block>) -> Result<CartePS, CartePSError> {
}
(2..=16, 1) => {
carte_ps.situations.push(SituationPS::default());
get_last_mut_situation(&mut carte_ps)?
carte_ps
.situations
.last_mut()
.unwrap()
.numero_logique_de_la_situation_de_facturation_du_ps = field.content[0];
}
(2..=16, 2) => {
get_last_mut_situation(&mut carte_ps)?.mode_d_exercice =
carte_ps.situations.last_mut().unwrap().mode_d_exercice =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 3) => {
get_last_mut_situation(&mut carte_ps)?.statut_d_exercice =
carte_ps.situations.last_mut().unwrap().statut_d_exercice =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 4) => {
get_last_mut_situation(&mut carte_ps)?.secteur_d_activite =
carte_ps.situations.last_mut().unwrap().secteur_d_activite =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 5) => {
get_last_mut_situation(&mut carte_ps)?.type_d_identification_structure =
carte_ps
.situations
.last_mut()
.unwrap()
.type_d_identification_structure =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 6) => {
get_last_mut_situation(&mut carte_ps)?.numero_d_identification_structure =
carte_ps
.situations
.last_mut()
.unwrap()
.numero_d_identification_structure =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 7) => {
get_last_mut_situation(&mut carte_ps)?
carte_ps
.situations
.last_mut()
.unwrap()
.cle_du_numero_d_identification_structure =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 8) => {
get_last_mut_situation(&mut carte_ps)?.raison_sociale_structure =
carte_ps
.situations
.last_mut()
.unwrap()
.raison_sociale_structure =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 9) => {
get_last_mut_situation(&mut carte_ps)?
carte_ps
.situations
.last_mut()
.unwrap()
.numero_d_identification_de_facturation_du_ps =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 10) => {
get_last_mut_situation(&mut carte_ps)?
carte_ps
.situations
.last_mut()
.unwrap()
.cle_du_numero_d_identification_de_facturation_du_ps =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 11) => {
get_last_mut_situation(&mut carte_ps)?
carte_ps
.situations
.last_mut()
.unwrap()
.numero_d_identification_du_ps_remplaçant =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 12) => {
get_last_mut_situation(&mut carte_ps)?
carte_ps
.situations
.last_mut()
.unwrap()
.cle_du_numero_d_identification_du_ps_remplaçant =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 13) => {
get_last_mut_situation(&mut carte_ps)?.code_conventionnel =
carte_ps.situations.last_mut().unwrap().code_conventionnel =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 14) => {
get_last_mut_situation(&mut carte_ps)?.code_specialite =
carte_ps.situations.last_mut().unwrap().code_specialite =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 15) => {
get_last_mut_situation(&mut carte_ps)?.code_zone_tarifaire =
carte_ps.situations.last_mut().unwrap().code_zone_tarifaire =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 16) => {
get_last_mut_situation(&mut carte_ps)?.code_zone_ik =
carte_ps.situations.last_mut().unwrap().code_zone_ik =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 17) => {
get_last_mut_situation(&mut carte_ps)?.code_agrement_1 =
carte_ps.situations.last_mut().unwrap().code_agrement_1 =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 18) => {
get_last_mut_situation(&mut carte_ps)?.code_agrement_2 =
carte_ps.situations.last_mut().unwrap().code_agrement_2 =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 19) => {
get_last_mut_situation(&mut carte_ps)?.code_agrement_3 =
carte_ps.situations.last_mut().unwrap().code_agrement_3 =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 20) => {
get_last_mut_situation(&mut carte_ps)?.habilitation_à_signer_une_facture =
carte_ps
.situations
.last_mut()
.unwrap()
.habilitation_à_signer_une_facture =
String::from_utf8_lossy(field.content).to_string();
}
(2..=16, 21) => {
get_last_mut_situation(&mut carte_ps)?.habilitation_à_signer_un_lot =
carte_ps
.situations
.last_mut()
.unwrap()
.habilitation_à_signer_un_lot =
String::from_utf8_lossy(field.content).to_string();
}
_ => {
return Err(CartePSError::UnknownGroupFieldPair {
group: group.id,
field: field.id,
});
return Err(format!(
"Unknown (group, field) pair: ({}, {})",
group.id, field.id
))
}
}
}
@ -271,7 +279,7 @@ mod test_decode_carte_ps {
57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53, 48, 2, 49,
48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
];
let blocks = decode_ssv_memory(bytes, bytes.len()).unwrap();
let blocks = decode_ssv_memory(bytes, bytes.len());
let carte_ps = decode_carte_ps(blocks).unwrap();
assert_eq!(carte_ps.titulaire.type_de_carte_ps, "0");
@ -362,7 +370,7 @@ mod test_decode_carte_ps {
57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53, 48, 2, 49,
48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
];
let blocks = decode_ssv_memory(bytes, bytes.len()).unwrap();
let blocks = decode_ssv_memory(bytes, bytes.len());
let carte_ps = decode_carte_ps(blocks).unwrap();
assert_eq!(carte_ps.situations.len(), 3);

View File

@ -1,4 +1,5 @@
pub mod cps;
pub mod cartevitale;
pub mod libssv;
pub mod ssv_memory;
pub mod ssvlib_demo;

View File

@ -3,13 +3,6 @@
/// Low level bindings to the SSVLIB dynamic library.
// TODO : look for creating a dedicated *-sys crate : https://kornel.ski/rust-sys-crate
use libc::{c_char, c_ushort, c_void, size_t};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum LibSSVError {
#[error("SSV library error in {function}: {code}")]
StandardErrorCode { code: u16, function: &'static str },
}
#[cfg_attr(target_os = "linux", link(name = "ssvlux64"))]
#[cfg_attr(target_os = "windows", link(name = "ssvw64"))]
@ -26,5 +19,13 @@ extern "C" {
ZDonneesSortie: *mut *mut c_void,
TTailleDonneesSortie: *mut size_t,
) -> c_ushort;
pub fn SSV_LireDroitsVitale(
NomRessourcePS: *const c_char,
NomRessourceLecteur: *const c_char,
CodePorteurPS: *const c_char,
DateConsultation: *const c_char,
ZDonneesSortie: *mut *mut c_void,
TTailleDonneesSortie: *mut size_t,
) -> c_ushort;
}
// TODO : replace void* by Rust struct : https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs

View File

@ -1,10 +1,9 @@
mod cps;
mod cartevitale;
mod libssv;
mod ssv_memory;
mod ssvlib_demo;
use anyhow::{Context, Result};
fn main() -> Result<()> {
ssvlib_demo::demo().context("Error while running the SSV library demo")
fn main() {
ssvlib_demo::demo();
}

View File

@ -1,33 +1,6 @@
/// # SSV Memory
/// Provide functions to manipulate raw memory from SSV library.
use std::convert::TryFrom;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum BytesReadingError {
#[error("Empty bytes input")]
EmptyBytes,
#[error("Invalid memory: not enough bytes ({actual}) to read the expected size ({expected})")]
InvalidSize { expected: usize, actual: usize },
#[error("Invalid memory: size ({actual}) is expected to be less than {expected} bytes")]
SizeTooBig { expected: usize, actual: usize },
#[error("Invalid memory: not enough bytes to read the block id")]
InvalidBlockId(#[from] std::array::TryFromSliceError),
#[error("Error while reading field at offset {offset}")]
InvalidField {
source: Box<BytesReadingError>,
offset: usize,
},
}
#[derive(Debug, Error)]
pub enum SSVMemoryError {
#[error("Error while parsing block at offset {offset}")]
BlockParsing {
source: BytesReadingError,
offset: usize,
},
}
#[derive(PartialEq, Debug)]
struct ElementSize {
@ -36,12 +9,13 @@ struct ElementSize {
}
// TODO : Est-ce qu'on pourrait/devrait définir un type custom pour représenter les tableaux de bytes ?
impl TryFrom<&[u8]> for ElementSize {
type Error = BytesReadingError;
type Error = &'static str;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.is_empty() {
return Err(BytesReadingError::EmptyBytes);
return Err("Empty bytes input");
}
let mut element_size = ElementSize { size: 0, pad: 1 };
@ -56,15 +30,9 @@ impl TryFrom<&[u8]> for ElementSize {
// N are the 7 lower bits of the first byte
let size_bytes_len = (bytes[0] & 0b0111_1111) as usize;
if size_bytes_len > bytes.len() - 1 {
return Err(BytesReadingError::InvalidSize {
expected: size_bytes_len,
actual: bytes.len() - 1,
});
return Err("Invalid memory: not enough bytes to read the size");
} else if size_bytes_len > 4 {
return Err(BytesReadingError::SizeTooBig {
expected: 4,
actual: size_bytes_len,
});
return Err("Invalid memory: size is too big");
}
let size_bytes = &bytes[1..1 + size_bytes_len];
@ -86,21 +54,15 @@ pub struct Block<'a> {
pub content: Vec<Field<'a>>,
}
impl<'a> TryFrom<&'a [u8]> for Block<'a> {
type Error = BytesReadingError;
fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
impl<'a> From<&'a [u8]> for Block<'a> {
fn from(bytes: &'a [u8]) -> Self {
let mut offset = 0;
let id = u16::from_be_bytes(
bytes[..2]
.try_into()
.map_err(BytesReadingError::InvalidBlockId)?,
);
let id = u16::from_be_bytes(bytes[..2].try_into().unwrap());
offset += 2;
let ElementSize {
size: block_size,
pad,
} = bytes[2..].try_into()?;
} = bytes[2..].try_into().unwrap();
offset += pad;
let raw_content = &bytes[offset..];
let mut field_offset = 0;
@ -108,22 +70,19 @@ impl<'a> TryFrom<&'a [u8]> for Block<'a> {
let mut content = Vec::new();
let mut field_id = 1;
while field_offset < block_size {
let mut field: Field<'a> = raw_content[field_offset..].try_into().map_err(|err| {
BytesReadingError::InvalidField {
source: Box::new(err),
offset: field_offset,
}
})?;
let mut field: Field<'a> = raw_content[field_offset..].into();
field.id = field_id;
field_offset += field.size;
field_id += 1;
content.push(field);
}
Ok(Block {
Block {
id,
size: offset + block_size,
content,
})
}
}
}
@ -134,41 +93,31 @@ pub struct Field<'a> {
pub content: &'a [u8],
}
impl<'a> TryFrom<&'a [u8]> for Field<'a> {
type Error = BytesReadingError;
fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
let ElementSize { size, pad } = bytes.try_into()?;
impl<'a> From<&'a [u8]> for Field<'a> {
fn from(bytes: &'a [u8]) -> Self {
let ElementSize { size, pad } = bytes.try_into().unwrap();
let contenu = &bytes[pad..pad + size];
Ok(Field {
Field {
id: 0,
size: pad + size,
content: contenu,
})
}
}
}
pub fn decode_ssv_memory(bytes: &[u8], size: usize) -> Result<Vec<Block>, SSVMemoryError> {
pub fn decode_ssv_memory(bytes: &[u8], size: usize) -> Vec<Block> {
let mut blocks: Vec<Block> = Vec::new();
let mut offset = 0;
while offset < size {
let block: Block =
bytes[offset..]
.try_into()
.map_err(|err| SSVMemoryError::BlockParsing {
source: err,
offset,
})?;
let block: Block = bytes[offset..].into();
offset += block.size;
blocks.push(block);
}
Ok(blocks)
blocks
}
#[cfg(test)]
mod test_element_size {
use std::any::Any;
use super::*;
#[test]
@ -195,51 +144,29 @@ mod test_element_size {
#[test]
fn null_size() {
let bytes: &[u8] = &[];
let result: Result<ElementSize, BytesReadingError> = bytes.try_into();
assert!(result.is_err());
assert_eq!(
result.unwrap_err().type_id(),
BytesReadingError::EmptyBytes.type_id()
);
let result: Result<ElementSize, &str> = bytes.try_into();
assert_eq!(result, Err("Empty bytes input"),);
}
#[test]
fn invalid_memory() {
let bytes: &[u8] = &[0b_1000_0001_u8];
let result: Result<ElementSize, BytesReadingError> = bytes.try_into();
assert!(result.is_err());
let result: Result<ElementSize, &str> = bytes.try_into();
assert_eq!(
result.unwrap_err().to_string(),
BytesReadingError::InvalidSize {
expected: 1,
actual: 0
}
.to_string()
result,
Err("Invalid memory: not enough bytes to read the size"),
);
let bytes: &[u8] = &[0b_1000_0010_u8, 1];
let result: Result<ElementSize, BytesReadingError> = bytes.try_into();
assert!(result.is_err());
let result: Result<ElementSize, &str> = bytes.try_into();
assert_eq!(
result.unwrap_err().to_string(),
BytesReadingError::InvalidSize {
expected: 2,
actual: 1
}
.to_string()
result,
Err("Invalid memory: not enough bytes to read the size"),
);
let bytes: &[u8] = &[0b_1000_0101_u8, 1, 1, 1, 1, 1];
let result: Result<ElementSize, BytesReadingError> = bytes.try_into();
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
BytesReadingError::SizeTooBig {
expected: 4,
actual: 5
}
.to_string()
);
let result: Result<ElementSize, &str> = bytes.try_into();
assert_eq!(result, Err("Invalid memory: size is too big"),);
}
}
@ -254,7 +181,7 @@ mod test_field {
80, 72, 65, 82, 77, 65, 67, 73, 69, 78, 48, 48, 53, 50, 52, 49, 57, 9, 70, 82, 65, 78,
67, 79, 73, 83, 69, 1, 84,
];
let element: Field = bytes.try_into().unwrap();
let element: Field = bytes.into();
assert_eq!(element.size, 52);
assert_eq!(element.content[..5], [1, 48, 1, 56, 11]);
}
@ -269,7 +196,7 @@ mod test_field {
// Add 256 bytes to the content
bytes_vec.append(&mut vec![1; 256]);
let bytes: &[u8] = &bytes_vec;
let element: Field = bytes.try_into().unwrap();
let element: Field = bytes.into();
assert_eq!(element.size, 259);
assert_eq!(element.content.len(), 256);
}
@ -283,15 +210,15 @@ mod test_block {
fn test_francoise_pharmacien0052419_partial_block_1() {
let bytes: &[u8] = &[1, 48, 1, 56, 11, 57, 57, 55, 48, 48, 53, 50, 52, 49, 57, 52];
let field1: Field = bytes.try_into().unwrap();
let field1: Field = bytes.into();
assert_eq!(field1.size, 2);
assert_eq!(field1.content, &[48]);
let field2: Field = bytes[field1.size..].try_into().unwrap();
let field2: Field = bytes[field1.size..].into();
assert_eq!(field2.size, 2);
assert_eq!(field2.content, &[56]);
let field3: Field = bytes[field1.size + field2.size..].try_into().unwrap();
let field3: Field = bytes[field1.size + field2.size..].into();
assert_eq!(field3.size, 12);
assert_eq!(
field3.content,
@ -318,12 +245,12 @@ mod test_block {
48, 2, 49, 48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
];
let first_block: Block = bytes.try_into().unwrap();
let first_block: Block = bytes.into();
assert_eq!(first_block.id, 1);
assert_eq!(first_block.size, 54);
assert_eq!(first_block.content.len(), 8);
let second_block: Block = bytes[first_block.size..].try_into().unwrap();
let second_block: Block = bytes[first_block.size..].into();
assert_eq!(second_block.id, 2);
assert_eq!(second_block.size, 86);
assert_eq!(second_block.content.len(), 21);
@ -352,7 +279,7 @@ mod test_decode_ssv_memory {
50, 50, 49, 57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53,
48, 2, 49, 48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
];
let blocks = decode_ssv_memory(bytes, bytes.len()).unwrap();
let blocks = decode_ssv_memory(bytes, bytes.len());
assert_eq!(blocks.len(), 2);
}
}

View File

@ -1,56 +1,33 @@
/// High level API for the SSV library,
/// based on the low level bindings in libssv.rs.
extern crate dotenv;
use libc::{c_void, size_t};
use std::env;
use std::ffi::CString;
use std::path::PathBuf;
use std::ptr;
use thiserror::Error;
use crate::cps::lire_carte;
use crate::cartevitale::LireDroitsVitale;
use crate::libssv::{SSV_InitLIB2, SSV_LireConfig};
use ::utils::config::load_config;
#[derive(Error, Debug)]
pub enum SSVDemoError {
#[error(transparent)]
CartePSReading(#[from] crate::cps::CartePSError),
#[error(transparent)]
SSVLibErrorCode(#[from] crate::libssv::LibSSVError),
#[error(transparent)]
Anyhow(#[from] anyhow::Error),
}
fn ssv_init_lib_2() -> Result<(), SSVDemoError> {
fn ssv_init_lib_2() {
let ini_str = env::var("SESAM_INI_PATH").expect("SESAM_INI_PATH must be set");
let ini = CString::new(ini_str).expect("CString::new failed");
unsafe {
let result = SSV_InitLIB2(ini.as_ptr());
println!("SSV_InitLIB2 result: {}", result);
if result != 0 {
return Err(crate::libssv::LibSSVError::StandardErrorCode {
code: result,
function: "SSV_InitLIB2",
}
.into());
}
}
Ok(())
}
fn ssv_lire_config() -> Result<(), SSVDemoError> {
fn ssv_lire_config() {
let mut buffer: *mut c_void = ptr::null_mut();
let mut size: size_t = 0;
unsafe {
let result = SSV_LireConfig(&mut buffer, &mut size);
println!("SSV_LireConfig result: {}", result);
if result != 0 {
return Err(crate::libssv::LibSSVError::StandardErrorCode {
code: result,
function: "SSV_LireConfig",
}
.into());
}
if !buffer.is_null() {
let hex_values = std::slice::from_raw_parts(buffer as *const u8, size);
@ -62,26 +39,30 @@ fn ssv_lire_config() -> Result<(), SSVDemoError> {
libc::free(buffer);
}
}
Ok(())
}
pub fn demo() -> Result<(), SSVDemoError> {
pub fn demo() {
// TODO : this is probably not working on release, because I'm not sure it exists a CARGO_MANIFEST_DIR and so it can find the `.env`
// Maybe we could use a system standard config path to store a config file
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let manifest_path = PathBuf::from(manifest_dir);
dotenv::from_path(manifest_path.join(".env")).ok();
println!("------- Demo for the SSV library --------");
load_config()?;
ssv_init_lib_2()?;
ssv_init_lib_2();
let code_pin = "1234";
let lecteur = "HID Global OMNIKEY 3x21 Smart Card Reader 0";
let carte_ps = lire_carte(code_pin, lecteur)?;
let lecteurvitale = "HID Global OMNIKEY 3x21 Smart Card Reader 1";
let dateconsultation ="20240813";
let carte_ps = lire_carte(code_pin, lecteur).unwrap();
println!("CartePS: {:#?}", carte_ps);
ssv_lire_config()?;
ssv_lire_config();
let carte_vitale = LireDroitsVitale(lecteur, lecteurvitale, code_pin, dateconsultation).unwrap();
println!("carte_vitale: {:#?}", carte_vitale);
println!("-----------------------------------------");
Ok(())
}

View File

@ -3,3 +3,4 @@ EXPORTS
SSV_InitLIB2
SSV_LireCartePS
SSV_LireConfig
SSV_LireDroitsVitale

View File

@ -1,9 +0,0 @@
[package]
name = "utils"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0"
directories = "5.0"
dotenv = "0.15"

View File

@ -1,48 +0,0 @@
use std::{env, path::PathBuf};
use anyhow::{bail, Context, Result};
use directories::ProjectDirs;
use dotenv::from_path;
const CONFIG_FILE_NAME: &str = ".env";
pub fn get_config_dirs() -> Vec<PathBuf> {
let mut config_dirs = vec![
PathBuf::from(""), // Current directory
];
if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
config_dirs.push(PathBuf::from(manifest_dir));
}
if let Some(proj_dirs) = ProjectDirs::from("org", "P4pillon", "Krys4lide") {
config_dirs.push(proj_dirs.config_dir().to_path_buf());
}
config_dirs
}
pub fn get_config_files() -> Result<Vec<PathBuf>> {
let config_dirs = get_config_dirs();
let mut config_files = Vec::new();
for config_dir in config_dirs.iter() {
let config_file = config_dir.join(CONFIG_FILE_NAME);
if config_file.exists() {
config_files.push(config_file);
}
}
if config_files.is_empty() {
bail!(
"No config file {CONFIG_FILE_NAME} found in the following directories: {config_dirs:#?}"
);
}
Ok(config_files)
}
pub fn load_config() -> Result<()> {
let config_files = get_config_files()?;
// Load the first config file found
// TODO: add a verbose log to list all config files found
println!(
"DEBUG: Config files found (1st loaded): {:#?}",
config_files
);
from_path(config_files[0].as_path()).context("Failed to load config file")
}

View File

@ -1 +0,0 @@
pub mod config;

View File

@ -1,85 +0,0 @@
# Gestion des erreurs
Ce document décrit comment les erreurs sont gérées dans le projet.
## Gestion native
Par principe, en Rust, on évite au maximum la gestion par exception, ne la réservant qu'aux situations où un crash du programme est la meilleure solution.
En temps normal, on renvoie des `Result<Valeur, Erreur>` (pour les situations réussite/erreur) ou des `Option<Valeur>` (pour les situations valeur non-nulle/nulle).
Quand on fait face à une situation d'erreur, on cherchera à la gérer de manière explicite (voir [Récupération des erreurs](#récupération-des-erreurs)) ou à la remonter à un niveau supérieur, généralement à l'aide de l'opérateur `?`.
On évitera, par contre, au maximum de générer des exceptions (appelées "panics" en Rust), que ce soit par l'usage de `panic!` ou par des appels à des fonctions qui paniquent en cas d'erreur (comme `unwrap` ou `expect`).
De nombreux exemples des idiomes natifs de gestion des erreurs en Rust sont disponibles dans la documentation [Rust by example](https://doc.rust-lang.org/rust-by-example/error.html).
## Librairies de gestion des erreurs
Deux librairies sont utilisées pour gérer les erreurs dans le projet :
- [`anyhow`](https://docs.rs/anyhow/latest/anyhow/) : qui permet de renvoyer des erreurs faiblement typées, mais très facile à enrichir avec des messages d'explication. On l'utilise pour communiquer facilement des erreurs de haut niveau avec un utilisateur final.
```rust
use anyhow::{anyhow, Result};
fn get_cluster_info() -> Result<ClusterInfo> {
let data = fs::read_to_string("cluster.json")
.with_context(|| "failed to read cluster config")?;
let info: ClusterInfo = serde_json::from_str(&data)
.with_context(|| "failed to parse cluster config")?;
Ok(info)
}
```
- [`thiserror`](https://docs.rs/thiserror/latest/thiserror/) : qui fournit des macros pour définir des erreurs fortement typées. On l'utilise pour définir des erreurs spécifiques à une partie du code, contextualisées avec des données structurées plutôt que de simples messages d'erreurs, afin de favoriser la "récupération" face aux erreurs.
```rust
use thiserror::Error;
#[derive(Error, Debug)]
pub enum DataStoreError {
#[error("data store disconnected")]
Disconnect(#[from] io::Error),
#[error("the data for key `{0}` is not available")]
Redaction(String),
#[error("invalid header (expected {expected:?}, found {found:?})")]
InvalidHeader {
expected: String,
found: String,
},
#[error("unknown data store error")]
Unknown,
}
```
## Récupération des erreurs
Dans la mesure du possible, on essaie de privilégier la "récupération" face à une erreur plutôt que le "crash". Les stratégies de récupération sont :
- Réessayer l'opération, tel quel ou avec des paramètres différents
- Contourner l'opération, en la remplaçant par une autre
- À défaut, informer l'utilisateur de l'erreur et :
- arrêter / annuler l'opération en cours
- ignorer l'erreur et continuer l'exécution
Quand on ne peut pas récupérer une erreur, on la remonte à un niveau supérieur, si besoin en la convertissant dans un type d'erreur plus générique et approprié au niveau considéré.
## Conversion des erreurs
Quand on remonte une erreur à un niveau supérieur, on peut être amené à la convertir dans un type d'erreur plus générique et approprié au niveau considéré. Pour faciliter cette conversion, on implémente le trait `From`. Avec `thiserror`, on peut utiliser l'attribut `#[from]` ou le paramètre `source` pour automatiser l'implémentation de telles conversions.
On peut ensuite, lors de la gestion d'une erreur, on pourra :
- soit directement renvoyer l'erreur à l'aide de l'opérateur `?`, qui se chargera de la conversion ;
- soit convertir l'erreur explicitement, par exemple en utilisant la méthode `map_err` sur un `Result`, en particulier quand on veut enrichir l'erreur avec des informations supplémentaires.
## Usages exceptionnels de `unwrap` et `expect`
Provoquant des "panics" en cas d'erreur, les fonctions `unwrap` et `expect` ne doivent être utilisées que dans des cas exceptionnels :
- Dans les tests, pour signaler une erreur de test
- Au plus haut niveau de l'application, pour signaler une erreur fatale qui ne peut pas être récupérée
- Dans des situations où l'erreur ne peut pas se produire, par exemple après une vérification de préconditions
Dans l'idéal, on préférera l'usage de `expect` à `unwrap`, car il permet de donner un message d'erreur explicite.
## Ressources
- [The Rust Programming Language - Ch. 9: Error Handling](https://doc.rust-lang.org/book/ch09-00-error-handling.html)
- [The NRC Book - Error Handling in Rust](https://nrc.github.io/error-docs/intro.html)
- [The Error Design Patterns Book - by Project Error Handling WG](https://github.com/rust-lang/project-error-handling/blob/master/error-design-patterns-book/src/SUMMARY.md)
- [The Rust Cookbook - Error Handling](https://rust-lang-nursery.github.io/rust-cookbook/error-handling.html)
- [Le ticket initial de l'intégration de la gestion des erreurs dans le projet](https://forge.p4pillon.org/P4Pillon/Krys4lide/issues/34)

24
frontend/.gitignore vendored
View File

@ -1,24 +0,0 @@
# Nuxt dev/build outputs
.output
.data
.nuxt
.nitro
.cache
dist
# Node dependencies
node_modules
# Logs
logs
*.log
# Misc
.DS_Store
.fleet
.idea
# Local env files
.env
.env.*
!.env.example

View File

@ -1,77 +0,0 @@
# Nuxt 3 Minimal Starter
TODO : Faire un vrai README pour `frontend` (Nuxt 3)
Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
## Setup
Make sure to install the dependencies:
```bash
# npm
npm install
# pnpm
pnpm install
# yarn
yarn install
# bun
bun install
```
## Development Server
Start the development server on `http://localhost:3000`:
```bash
# npm
npm run dev
# pnpm
pnpm run dev
# yarn
yarn dev
# bun
bun run dev
```
## Production
Build the application for production:
```bash
# npm
npm run build
# pnpm
pnpm run build
# yarn
yarn build
# bun
bun run build
```
Locally preview production build:
```bash
# npm
npm run preview
# pnpm
pnpm run preview
# yarn
yarn preview
# bun
bun run preview
```
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.

View File

@ -1,7 +0,0 @@
<template>
<div>
<NuxtRouteAnnouncer />
<NavBar />
<NuxtPage />
</div>
</template>

View File

@ -1,43 +0,0 @@
<!--
This component is used to show a loading spinner when the SPA is loading.
Source: https://github.com/barelyhuman/snips/blob/dev/pages/css-loader.md
-->
<div class="loader"></div>
<style>
.loader {
display: block;
position: fixed;
z-index: 1031;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 18px;
height: 18px;
box-sizing: border-box;
border: solid 2px transparent;
border-top-color: #000;
border-left-color: #000;
border-bottom-color: #efefef;
border-right-color: #efefef;
border-radius: 50%;
-webkit-animation: loader 400ms linear infinite;
animation: loader 400ms linear infinite;
}
\@-webkit-keyframes loader {
0% {
-webkit-transform: translate(-50%, -50%) rotate(0deg);
}
100% {
-webkit-transform: translate(-50%, -50%) rotate(360deg);
}
}
\@keyframes loader {
0% {
transform: translate(-50%, -50%) rotate(0deg);
}
100% {
transform: translate(-50%, -50%) rotate(360deg);
}
}
</style>

Binary file not shown.

View File

@ -1,22 +0,0 @@
<template>
<div class="avatar">
<div class="rounded-full">
<img :src="getAvatarUrl(user)" />
</div>
</div>
</template>
<script setup lang="ts">
import type { User } from '~/types/user';
const props = defineProps<{
user: User,
}>();
const getAvatarUrl = (user: User) => {
if (user.avatar) {
return user.avatar;
}
return 'https://avatar.iran.liara.run/username?username=' + user.name;
};
</script>

View File

@ -1,71 +0,0 @@
<template>
<dialog
id="login_modal"
ref="login_modal"
@cancel.prevent=""
@keyup="handleKeyPress"
class="modal"
>
<div class="modal-box">
<h3 class="text-3xl text-center mb-6">Connexion</h3>
<div class="flex flex-wrap gap-5 justify-center">
<template v-for="(user, index) in users" :key="user.id">
<LoginModalAvatar
:user="user"
:rank="index+1"
@selectUser="login"
/>
</template>
</div>
</div>
<form method="dialog" class="modal-backdrop">
<button class="cursor-default">close</button>
</form>
</dialog>
</template>
<script setup lang="ts">
import type { User } from '~/types/user';
const users: User[] = [
{ id: 1, name: 'John Doe', avatar: 'https://img.daisyui.com/images/stock/photo-1534528741775-53994a69daeb.webp' },
{ id: 2, name: 'Jane Doe', avatar: 'https://avatar.iran.liara.run/public' },
{ id: 3, name: 'Michel Moulin', avatar: '' },
{ id: 4, name: 'Jean Paris', avatar: '' },
{ id: 5, name: 'Marie Dupont', avatar: '' },
{ id: 6, name: 'Émilie Fournier', avatar: '' },
{ id: 7, name: 'Pierre Lefevre', avatar: '' },
{ id: 8, name: 'Sophie Lemoine', avatar: '' },
{ id: 9, name: 'Lucie Simon', avatar: '' },
{ id: 10, name: 'Kevin Boucher', avatar: '' },
];
const loginModal = useTemplateRef('login_modal');
const current_user = useCurrentUser();
const login = (user: User) => {
console.log('login', user);
current_user.value = user;
loginModal.value?.close();
};
const handleKeyPress = (event: KeyboardEvent) => {
// Extract the rank from the event.code : Digit7 -> 7
const rank = event.code.match(/\d/);
if (!rank) {
console.debug('Not handled key event', { event });
return;
}
const user = getUserByRank(parseInt(rank[0]));
if (user) {
login(user);
} else {
console.debug('Not handled key event', { event });
}
};
const getUserByRank = (rank: number): User => {
return users[rank - 1];
};
</script>

Some files were not shown because too many files have changed in this diff Show More