Skip to main content

Decentralized Instant Messaging Protocol (Python)

License PRs Welcome Platform Issues Repo Size Tags Version

Watchers Forks Stars Followers

Dependencies

  • Latest Versions
Name Version Description
Ming Ke Ming (名可名) Version Decentralized User Identity Authentication
Dao Ke Dao (道可道) Version Universal Message Module

Examples

Extends Command

  • Handshake Command Protocol 0. (C-S) handshake start
    1. (S-C) handshake again with new session
    2. (C-S) handshake restart with new session
    3. (S-C) handshake success
from abc import ABC, abstractmethod
from enum import IntEnum
from typing import Optional

from dimp import *


class HandshakeState(IntEnum):
    Start = 0    # C -> S, without session key(or session expired)
    Again = 1    # S -> C, with new session key
    Restart = 2  # C -> S, with new session key
    Success = 3  # S -> C, handshake accepted


def handshake_state(title: str, session: str = None) -> HandshakeState:
    # Server -> Client
    if title == 'DIM!':  # or title == 'OK!':
        return HandshakeState.Success
    if title == 'DIM?':
        return HandshakeState.Again
    # Client -> Server: "Hello world!"
    if session is None or len(session) == 0:
        return HandshakeState.Start
    else:
        return HandshakeState.Restart


class HandshakeCommand(Command, ABC):
    """
        Handshake Command
        ~~~~~~~~~~~~~~~~~

        data format: {
            "type" : i2s(0x88),
            "sn"   : 12345,

            "command" : "handshake",     // command name
            "title"   : "Hello world!",  // "DIM?", "DIM!"
            "session" : "{SESSION_KEY}", // session key
        }
    """
    HANDSHAKE = 'handshake'

    @property
    @abstractmethod
    def title(self) -> str:
        raise NotImplementedError(
            f'Not implemented: {type(self).__module__}.{type(self).__name__}.title getter'
        )

    @property
    @abstractmethod
    def session(self) -> Optional[str]:
        raise NotImplementedError(
            f'Not implemented: {type(self).__module__}.{type(self).__name__}.session getter'
        )

    @property
    @abstractmethod
    def state(self) -> HandshakeState:
        raise NotImplementedError(
            f'Not implemented: {type(self).__module__}.{type(self).__name__}.state getter'
        )

    #
    #   Factories
    #

    @classmethod
    def offer(cls, session: str = None) -> Command:
        """
        Create client-station handshake offer

        :param session: Old session key
        :return: HandshakeCommand object
        """
        return BaseHandshakeCommand(title='Hello world!', session=session)

    @classmethod
    def ask(cls, session: str) -> Command:
        """
        Create station-client handshake again with new session

        :param session: New session key
        :return: HandshakeCommand object
        """
        return BaseHandshakeCommand(title='DIM?', session=session)

    @classmethod
    def accepted(cls, session: str = None) -> Command:
        """
        Create station-client handshake success notice

        :return: HandshakeCommand object
        """
        return BaseHandshakeCommand(title='DIM!', session=session)

    start = offer       # (1. C->S) first handshake, without session
    again = ask         # (2. S->C) ask client to handshake with new session key
    restart = offer     # (3. C->S) handshake with new session key
    success = accepted  # (4. S->C) notice the client that handshake accepted
from collections.abc import Mapping
from typing import Optional

from dimp import *


class BaseHandshakeCommand(BaseCommand, HandshakeCommand):

    def __init__(self, content: Mapping = None, title: str = None, session: str = None):
        if content is None:
            # 1. new command with title & session key
            assert title is not None, 'handshake command error: %s' % session
            cmd = self.HANDSHAKE
            super().__init__(cmd=cmd)
            self['title'] = title
            self['message'] = title  # TODO: remove after all clients upgraded
            if session is not None:
                self['session'] = session
        else:
            # 2. command info from network
            assert title is None and session is None, 'params error: %s, %s, %s' % (content, title, session)
            super().__init__(content)

    @property
    def title(self) -> str:
        return self.get_str(key='title', default='')

    @property
    def session(self) -> Optional[str]:
        return self.get_str(key='session')

    @property
    def state(self) -> HandshakeState:
        return handshake_state(title=self.title, session=self.session)

Extends Content

from abc import ABC, abstractmethod

from dimp import *


class AppContent(Content, ABC):
    """
        Content for Application 0nly
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        data format: {
            "type" : i2s(0xA0),
            "sn"   : 12345,

            "app"   : "{APP_ID}",  // application (e.g.: "chat.dim.sechat")
            "extra" : info         // action parameters
        }
    """

    @property
    @abstractmethod
    def application(self) -> str:
        """ App ID """
        raise NotImplementedError(
            f'Not implemented: {type(self).__module__}.{type(self).__name__}.application getter'
        )


class CustomizedContent(Content, ABC):
    """
        Application Customized message
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        data format: {
            "type" : i2s(0xCC),
            "sn"   : 12345,

            "app"   : "{APP_ID}",  // application (e.g.: "chat.dim.sechat")
            "mod"   : "{MODULE}",  // module name (e.g.: "drift_bottle")
            "act"   : "{ACTION}",  // action name (e.g.: "throw")
            "extra" : info         // action parameters
        }
    """

    @property
    @abstractmethod
    def module(self) -> str:
        """ Module Name """
        raise NotImplementedError(
            f'Not implemented: {type(self).__module__}.{type(self).__name__}.module getter'
        )

    @property
    @abstractmethod
    def action(self) -> str:
        """ Action Name """
        raise NotImplementedError(
            f'Not implemented: {type(self).__module__}.{type(self).__name__}.action getter'
        )

    #
    #   Factory method
    #
    @classmethod
    def create(cls, app: str, mod: str, act: str):
        return AppCustomizedContent(app=app, mod=mod, act=act)
from collections.abc import Mapping

from dimp import *


class AppCustomizedContent(BaseContent, AppContent, CustomizedContent):

    def __init__(self, content: Mapping = None,
                 msg_type: str = None,
                 app: str = None, mod: str = None, act: str = None):
        if content is None:
            # 1. new content with type, application, module & action
            assert app is not None and mod is not None and act is not None, \
                'customized content error: %s, %s, %s, %s' % (msg_type, app, mod, act)
            if msg_type is None:
                msg_type = ContentType.CUSTOMIZED
            super().__init__(None, msg_type)
            self['app'] = app
            self['mod'] = mod
            self['act'] = act
        else:
            # 2. content info from network
            assert msg_type is None and app is None and mod is None and act is None, \
                'params error: %s, %s, %s, %s, %s' % (content, msg_type, app, mod, act)
            super().__init__(content)

    @property  # Override
    def application(self) -> str:
        return self.get_str(key='app', default='')

    @property  # Override
    def module(self) -> str:
        return self.get_str(key='mod', default='')

    @property  # Override
    def action(self) -> str:
        return self.get_str(key='act', default='')

Extends ID Address


Copyright © 2018-2026 Albert Moky Followers

Release files for dimp 2.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dimp 2.5.0
File Size Uploaded
dimp-2.5.0.tar.gz 23.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dimp 2.5.0
File Interpreter ABI Platform
dimp-2.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 65.4 kB

Release files / dimp-2.5.0.tar.gz

Download URL dimp-2.5.0.tar.gz
Size 23.2 kB
Tags Source
SHA-256 checksum
How to use checksums
5a66311e54417fa962555d9bc0308bd4e7ea0f5e9583266d70986548c6d43744
BLAKE2b-256 checksum
How to use checksums
413d58126b411e0e56e70d280182cfb4ccef020a11459aaac58be25bf88488f9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/68.0.0 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.7.0b3

Release files / dimp-2.5.0-py3-none-any.whl

Download URL dimp-2.5.0-py3-none-any.whl
Size 42.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b65f1045ca510748a0f538202eed0dfdfdb858b967e462202dd232ef92462f5f
BLAKE2b-256 checksum
How to use checksums
7c8f5e0652bf7d3832570a0a08563011ca583b69df355bee81e60d37ac117603
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/68.0.0 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.7.0b3

Release history Release notifications | RSS feed

This release

2.5.0 This release

2 release files

2.4.3

2 release files

2.4.2

2 release files

2.4.1

2 release files

2.4.0

2 release files

2.3.4

2 release files

2.3.3

2 release files

2.3.2

2 release files

2.3.1

2 release files

2.3.0

2 release files

2.2.2

2 release files

2.2.1

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

0.12.6

2 release files

0.12.4

2 release files

0.12.2

2 release files

0.12.1

2 release files

0.12.0

2 release files

0.11.6

2 release files

0.11.1

2 release files

0.9.8

2 release files

0.9.7

2 release files

0.9.6

2 release files

0.9.5

2 release files

0.9.3

2 release files

0.9.2

2 release files

0.8.12

2 release files

0.8.11

2 release files

0.8.10

2 release files

0.8.9

2 release files

0.8.8

2 release files

0.8.6

2 release files

0.8.5

2 release files

0.8.3

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.7.10

2 release files

0.7.8

2 release files

0.7.6

2 release files

0.7.5

2 release files

0.7.4

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.6

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.4

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.12

2 release files

0.4.9

2 release files

0.4.8

2 release files

0.4.7

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.0

2 release files

0.3.9

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.3

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page