jkl
(10-04-2017, 07:49 AM)pyratebeard Wrote: Does anybody start ricing a new application after installing (and RTFM) instead of using it first?

Yup - Rainlendar. :)
(Not on Unix though.)

On Unix: Firefox and awesome WM. (Because Firefox needs a couple of extensions to be usable enough for me, and awesome WM lacks a good default menu.)
evbo
I have no mind for good color schemes or visual layouts, so my ricing comes from a need for function, not aesthetics. To be honest, I usually will just steal a nice looking color scheme (Thanks xero for sourcerer, currently using it on dwm/st and neovim), then build the most efficient workflow I can.
Halfwit
I've never heard the edit of this yet, wow this turned out great!
Halfwit
(Also minor edit, I renamed ubqt to altid, located now at https://github.com/altid. Ubqt was used just everywhere)
josuah
(05-04-2020, 01:41 AM)Halfwit Wrote: (Also minor edit, I renamed ubqt to altid, located now at https://github.com/altid. Ubqt was used just everywhere)

That made me learn about Ubqt, hum, Altid, which is really nice ! I did not test it yet, but that is definitely a nice way to expose all these services out.

I like that vision with putting all different kinds of services though a same protocol, because such a waste of time wasted writing code for parsing protocols! (IMAP for instance...)

Instead of 9P + directory layout, the world seems to go the way of HTTP + JSON + JSON layout... I still prefer dedicated protocols (yeah, I'd rather waste this time) to go for better protocols than HTTP which is_terrible_ at serializing things.

HTTP is no smarter than FTP if you think of it: 9P is a single TCP/TLS/SSH/CurveCP/MinimaLT/Quic/... stream to achieve something, so it does not suffer from tcp+tls overhead.

For converting all these zillion of protocols to HTTP, you have to do ONE REQUEST PER COMMAND! Such as IMAP LOGIN, then another one for LIST, then another one for SELECT, then another one for FETCH, and then so on.

So if you use HTTP for anything different than fetching individual files, it is NOT network transparent anymore!

Oh what? you have network-transparent HTTP2 that multiplexes streams? You'll only get that after ALPN negociation (TLS-specific) though.

Now HTTP3 is not directly bound to QUIC? It still does make use of its complex API, that only QUIC has.

Yes, mapping all protocols to 9P (including twitter, why not! if one uses it...) wil definitely be a better choice. Also, 9P does support notifications, thorugh a blocking read(2) call from the client, with the server that pushes bytes (maybe one at a time?) on each event. This is 256 kind of event, then the client can go rescan everything on updates.

Definitely sounds reasonable!

Code:
service=twitter handle=@Myhandle logdir=none secret=redacted token=redacted listen_address=none

NDB! How else to configure services... Maybe factotum? ;)

Code:
$ cat ndb.c
#include "ndb.h"

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <ctype.h>

/*
* The Network Datbase: a simple text-based key-value entrys file format:
* http://code.9front.org/hg/plan9front/file/c4896008f196/sys/src/libndb
*
* This implementation uses a singly linked list for the entire database,
* with all lines and entries chained on the same linked list, with an
* aditionnal pointer to the begining of the line, and another to the
* begining of the tuple:
*/

#include "log.h"

static void *
ndb_new(struct ndb **entry)
{
    struct ndb *np;

    if ((np = calloc(sizeof(struct ndb), 1)) == NULL)
        return (NULL);
    np->entry = *entry = *entry ? *entry : np;
    return (np);
}

void
ndb_free(struct ndb *np)
{
    if (np)
        ndb_free(np->next);
    free(np);
}

/*
* key = 1*keychar
* keychar = ( '0'..'9' | 'a'..'z' | 'A'..'Z' | '_' | '-' )
*/
static char *
ndb_parse_key(char *s, struct ndb *new)
{
    char *key;
    size_t len;

    key = s;
    while (*s != '\0' && (isalnum(*s) || strchr("_-", *s)))
        s++;
    if (s == key)
        return (NULL);
    len = s-key;

    if (len >= sizeof(new->key))
        return (errno=ENAMETOOLONG, NULL);
    memcpy(new->key, key, len);
    return (s);
}

/*
* val = ( '"' *quotedchar '"' | *unquotchar )
* quotedchar = ( 0x20..0x21 | 0x23..0x7E | 0x80..0xFF)
* unquotchar = ( 0x21 | 0x24..0x26 | 0x5D..0x7E | 0x80..0xFF)
*/
static char *
ndb_parse_val(char *s, struct ndb *new)
{
    char *val;
    size_t len;

    if (*s == '"') {
        s++;
        val = s;
        while (*s >= 0x20 && *s != '"' && *s != 0x7f)
            s++;
        len = s-val;
        if (*s++ != '"')
            return (NULL);
    } else {
        val = s;
        while (*s >= 0x21 && *s != '"' && *s != 0x7f)
            s++;
        len = s-val;
    }

    if (len >= sizeof(new->val))
        return (errno=ENAMETOOLONG, NULL);
    memcpy(new->val, val, len);
    return (s);
}

/*
* tuple = key '=' val
*/
static char *
ndb_parse_tuple(char *s, struct ndb **entry, struct ndb **last)
{
    struct ndb *new;

    if ((new = ndb_new(entry)) == NULL)
        return (NULL);

    if ((s = ndb_parse_key(s, new)) == NULL)
        goto err;

    if (*s++ != '=')
        goto err;

    if ((s = ndb_parse_val(s, new)) == NULL)
        goto err;

    if (*last != NULL)
        (*last)->next = new;
    *last = new;
    return (s);
err:
    free(new);
    return (NULL);
}

/*
* ws = ( '\t' | '\r' | ' ' )
*/
static char *
ndb_parse_ws(char *s)
{
    if (!isblank(*s) && *s != '\r')
        return (NULL);
    while (isblank(*s) || *s == '\r')
        s++;
    return (s);
}

/*
* nl = 1*( [ ws ] [ '#' *non-nl ] '\n' )
*/
static char *
ndb_parse_nl(char *s, size_t *nl)
{
    char *beg;
    size_t n;

    for (n = 0 ;; n++, (*nl)++) {
        beg = s;
        if ((s = ndb_parse_ws(s)) == NULL)
            s = beg;
        if (*s == '#') {
            while (*s != '\0' && *s != '\n')
                s++;
        }
        if (*s != '\n') {
            s = beg;
            break;
        }
        s++;
    }
    if (n == 0)
        return (NULL);
    return (s);
}

/*
* line = tuple *( 1*ws tuple ) nl
*/
static char *
ndb_parse_line(char *s, struct ndb **entry, struct ndb **last, size_t *nl)
{
    char *cp;

    if ((s = ndb_parse_tuple(s, entry, last)) == NULL)
        return (NULL);

    while ((cp = ndb_parse_ws(s))) {
        s = cp;

        if ((cp = ndb_parse_tuple(s, entry, last)) == NULL)
            break;
        s = cp;
    }

    return (ndb_parse_nl(s, nl));
}

/*
* entry = line *( 1*ws line )
*/
static char *
ndb_parse_entry(char *s, struct ndb **last, size_t *nl)
{
    struct ndb *entry = NULL;
    char *cp;

    if ((cp = ndb_parse_line(s, &entry, last, nl)) == NULL)
        return (NULL);
    s = cp;

    while ((cp = ndb_parse_ws(s))) {
        s = cp;

        if ((cp = ndb_parse_line(s, &entry, last, nl)) == NULL)
            break;
        s = cp;
    }
    return (errno ? NULL : s);
}

/*
* base = *nl *( tuple *nl )
*/
static char *
ndb_parse_db(char *s, struct ndb **db, struct ndb **last, size_t *nl)
{
    char *cp;

    while ((cp = ndb_parse_nl(s, nl)))
        s = cp;

    *db = NULL;
    while ((cp = ndb_parse_entry(s, last, nl))) {
        s = cp;

        if (*db == NULL)
            *db = (*last)->entry;

        while ((cp = ndb_parse_nl(s, nl)))
            s = cp;
    }
    return (errno ? NULL : s);
}

static ssize_t
readfile(char const *path, char **s)
{
    ssize_t r, n;
    void *v;
    int fd;

    if ((fd = (path == NULL) ? 0 : open(path, O_RDONLY)) == -1)
        return (-1);

    r = n = 0;
    *s = NULL;
    do {
        n += r;
        if ((v = realloc(*s, n + 2048 + 1)) == NULL) {
            r = -1;
            goto err;
        }
        *s = v;
    } while ((r = read(fd, *s + n, 2048)) > 0);
    (*s)[n] = '\0';
err:
    if (fd > 0)
        close(fd);
    if (r == -1) {
        free(*s);
        *s = NULL;
    }
    return (r);
}

struct ndb *
ndb_parse_file(char const *path, size_t *nl, struct ndb **last)
{
    struct ndb *db;
    ssize_t r;
    char *s;

    *nl = 0;
    db = NULL;

    if ((r = readfile(path, &s)) == -1)
        return (NULL);
    if (memchr(s, '\0', r)) {
        errno = EBADMSG;
        return (NULL);
    }

    *nl = 1;
    if (ndb_parse_db(s, &db, last, nl) < s + r) {
        errno = EBADMSG;
        ndb_free(db);
        db = NULL;
    }
    free(s);
    return (db);
}

struct ndb *
ndb_open(char const **path, size_t *nl)
{
    struct ndb *db, *last, *np, *entry, *file;

    last = NULL;

    if ((db = np = ndb_parse_file(*path, nl, &last)) == NULL)
        return (NULL);

    if ((np = ndb_search(&np, NULL, "database", "")) == NULL)
        return (db);

    entry = np = np->entry;
    while ((file = ndb_search(&np, entry, "file", NULL))) {
        if (ndb_parse_file(file->val, nl, &last) == NULL) {
            *path = strdup(file->val);
            ndb_free(db);
            return (NULL);
        }
    }
    return (db);
}

struct ndb *
ndb_search(struct ndb **npp, struct ndb *entry, char const *key, char const *val)
{
    for (struct ndb *np = *npp; np; np = np->next) {
        if (entry && np->entry != entry->entry)
            break;
        if (strcmp(np->key, key) == 0) {
            if (!val || fnmatch(val, np->val, 0) == 0) {
                *npp = np->next;
                return (np);
            }
        }
    }
    return (NULL);
}

struct ndb *
ndb_related(struct ndb *this, char const *key)
{
    struct ndb *np, *entry;

    entry = this->entry;
    for (np = entry; np && np->entry == entry; np = np->next)
        if (strcmp(np->key, key) == 0)
            return ( np);
    return (NULL);
}

void
ndb_put_tuple(FILE *fp, struct ndb *np)
{
    char *fmt;

    fmt = np->val[strcspn(np->val, " \t")] == '\0' ? "%s=%s" : "%s=\"%s\"";
    fprintf(fp, fmt, np->key, np->val);
}

void
ndb_put_entry(FILE *fp, struct ndb *np, int nl)
{
    struct ndb *entry;
    int first;

    first = 1;
    for (np = entry = np->entry; np && np->entry == entry; np = np->next) {
        if (!first)
            fprintf(fp, nl ? "\n\t" : " ");
        ndb_put_tuple(fp, np);
        first = 0;
    }
}
$ cat ndb.h
#ifndef NDB_H
#define NDB_H

#include <time.h>
#include <stdint.h>
#include <stdio.h>

struct ndb {
    char        key[32];
    char        val[128];
    struct ndb    *next;        /* across multiple lines or tuples */
    struct ndb    *entry;        /* start of this entry */
};

/**/
void        ndb_free        (struct ndb *);
struct ndb *    ndb_search        (struct ndb **, struct ndb *, char const *, char const *);
struct ndb *    ndb_related        (struct ndb *, char const *);
struct ndb *    ndb_parse_file        (char const *, size_t *, struct ndb **);
struct ndb *    ndb_open        (char const **, size_t *);
void        ndb_put_tuple        (FILE *, struct ndb *);
void        ndb_put_entry        (FILE *, struct ndb *, int);

#endif

Yes I share code by pasting them on forums. True LOONIX way! Watchagonnado?
venam
(08-04-2020, 04:03 PM)josuah Wrote: I like that vision with putting all different kinds of services though a same protocol, because such a waste of time wasted writing code for parsing protocols! (IMAP for instance...)

That reminds me of inetd and Systemd socket activation which are both implementation of the idea of super-server aka service dispatcher, listening on a tcp socket for events that tells it how to manage services.
jkl
Of those, inetd is notably less horrible, more reliable and - most importantly - available on most operating systems.
josuah
This is another proposal for socket activation, which makes use of fd-passing : http://skarnet.org/software/s6/socket-activation.html

This is for daemon which already started and receive client connexion _afterward_: it will have already-opened file descriptors: a fd-passing daemon that just holds your already opened files/sockets waiting to be grabbed by an AF_INET, or AF_UNIX socket or a pipe or ...

For something that can start a new process at every connexion, I'd probably go with inetd/ucspi as jkl said.

FD passing is a little bit obscure : you call this syscall with these parameters, and the argument is going to suddenly be considered as a file descriptor to be passed to the other process.

It is nicely wrapped up in plan9port (plan9port source code is the starting point of the Go programming language which just pulled the libraries for handling all the platform-specific thing and made a language out of it, p9p did a good job on portability) :

https://github.com/9fans/plan9port/blob/...9/sendfd.c

(Yesterday, 02:11 AM)venam Wrote: the idea of super-server

Well you are right for opening a socket is still parsing a protocol... I did not think of that.




Members  |  Stats  |  Night Mode