# Framework

## Features

* simple routes handler
* auto description to status code
* headers checker
* send data as soon as possible
* send strings, bytes, lists(even bytes and strings mixed) or files directly
* error catcher and error logger

**works with many WSGI compatible servers**

> you should use HTTP version **`1.1`** Server with your [WSGI](http://www.wsgi.org/) framework for some clients like Firefox browser

```python
from wsocket import WSocketApp, WebSocketError, logger, run
from time import sleep

logger.setLevel(10)  # for debugging

app = WSocketApp()
# app = WSocketApp(protocol="WAMP")

@app.route("/")
def handle_websocket(environ, start_response):

    wsock = environ.get("wsgi.websocket")

    if not wsock:
        start_response()
        return "Hello World!"

    while True:
        try:
            message = wsock.receive()
            if message != None:
                print("participator : " + message)
                wsock.send("you : "+message)
                sleep(2)
                wsock.send("you : "+message)
                
        except WebSocketError:
            break
            
run(app)
```

{% hint style="info" %}
see Websocket for more info on `wsgi.websocket` variable in WSGI environment dictionary.
{% endhint %}

{% content-ref url="websocket" %}
[websocket](https://wsocket.gitbook.io/docs/guide/websocket)
{% endcontent-ref %}

## WSocketApp

`class  WSocketApp(app=None, protocol=None)`

### Class variables

`GUID` - unique ID to generate websocket accept key

`SUPPORTED_VERSIONS` - 13, 8 or 7

`routes` - dictionary for route handlers

`websocket_class` - `"wsgi.websocket"` in WSGI Environ

#### Methods

`not_found(self, environ, start_response)` - handle `404 NOT FOUND` error

`route(self, r)` - register routes

## Routes

WSocket uses simple routes engine. How it works?

* URL -  `http://localhost:8080/hello/world?user=Ksengine&pass=1234`
* divided into parts(by Server)

  | origin | host        | port   | path           | query                     |
  | ------ | ----------- | ------ | -------------- | ------------------------- |
  | `http` | `localhost` | `8080` | `/hello/world` | `user=Ksengine&pass=1234` |

  &#x20; **only path is used to find routes**
* walk through routes dictionary
  * if `"/hello/world"` path found, trigger route handler

    ```python
    @app.route("/hello/world")
    ```

    * else, if some route string ends with "\*" and path starts with that string trigger route handler&#x20;

      ```python
      @app.route("/hello/world")
      ```

## Status and Headers

call `start_response` to send status code and headers. if you returns without calling it. It will send `200 OK` status and some basic headers to client. if `start_response` is called without argsuments, it will send `200 OK` status and some basic headers to client.

```python
start_response()
```

`start_response` has two arguments

* status - status code as int(eg:-200) or str(eg:- "200 OK" or "200"). If status description(eg:-"OK") not supplied, it will find it.
* headers - HTTP headers. can passed as,
  * list of tuples&#x20;

    ```python
    [("header1 name", "header1 value"),
    ("header2 name", "header2 value")  ]
    ```
  * dictionary

    ```python
    {"header1 name": "header1 value",
    "header2 name": "header2 value"}
    ```

status code examples:-

```python
start_response() # start_response("200 OK",[])
```

```python
start_response(200) # start_response("200 OK",[])
```

```python
start_response("200") # start_response("200 OK",[])
```

```python
start_response("200 OK") # start_response("200 OK",[])
```

send headers examples:-

* list of tuples

  ```python
    start_response("200 OK",[
        ("header1 name", "header1 value"),
        ("header2 name", "header2 value")
  ])
  ```
* dictionary

  ```python
   start_response("200 OK",{
    "header1 name": "header1 value",
    "header2 name": "header2 value"
  })
  ```

## Send data

You can send following data types

* `str` - string, text

  ```python
  def sender(environ, start_response)
      start_response()
      # ...some code here
      return "Hello World!"
  ```
* `bytes` - binary

  ```python
  def sender(environ, start_response)
      start_response()
      # ...some code here
      return b"Hello World!" # b"" is binary string
  ```

  ```python
  def sender(environ, start_response)
      start_response()
      # ...some code here
      return "Hello World!".encode() # str.encode converts str to bytes
  ```

  ```python
  def sender(environ, start_response)
      start_response()
      # ...some code here
      return b"Hello World!" # open file as text file
  ```
* `files` - opened files

  ```python
  def sender(environ, start_response)
      start_response()
      # ...some code here
      return open("hello.txt")
  ```

  ```python
  def sender(environ, start_response)
      start_response()
      # ...some code here
      return open("hello.txt", "b") # "b" - open as binary file
  ```
* `file-like object` - streams(text, binary) like `StringIO`or `BytesIO`

  ```python
   try:
       from io import StringIO
   except ImportError:
       from StringIO import StringIO

  def sender(environ, start_response)
      start_response()
      # ...some code here
      file_like = StringIO()
      return file_like
  ```

  ```python
   try:
       from io import BytesIO
   except ImportError:
       from StringIO import BytesIO

  def sender(environ, start_response)
      start_response()
      # ...some code here
      file_like = BytesIO()
      return file_like
  ```
* `iterables`  - `list`,  `tuple`, `set` `dict` `generators` etc.

  ```python
  def sender(environ, start_response)
      start_response()
      # ...some code here
      return ["Hello ", b"World", "!".encode(), 2020] # list
  ```

  ```python
  def sender(environ, start_response)
      start_response()
      # ...some code here
      return ("Hello ", b"World", "!".encode(), 2020) # tuple
  ```

  ```python
  def sender(environ, start_response)
      start_response()
      # ...some code here
      return {"Hello ", b"World", "!".encode(), 2020} # set
  ```

  ```python
  def sender(environ, start_response)
      start_response()
      # ...some code here
      return {"Hello ":None, "World!":None} # dict
  ```

  ```python
   import time
  def sender(environ, start_response)
      start_response()
      # ...some code here
      yield "Hello "
      time.sleep(2)
      yield b"World"
      time.sleep(5)
      yield "!".encode()
      yield 2020 # generators
  ```

  **generators can send data one by one with time intervals. so it's like async Server**
* other -

  ```python
  def sender(environ, start_response)
      start_response()
      # ...some code here
      return 3.3 # float
  ```

  **Errors**

  example :-

  > ## Internal Server Error(500)
  >
  > **ZeroDivisionError :division by zero**
  >
  > ```
  > Traceback (most recent call last):
  >  File "wsocket.py", line 881, in process_response
  >    results = self.app(self.environ, self.start_response)
  >  File "wsocket.py", line 1068, in wsgi
  >    1/0
  > ZeroDivisionError: division by zero
  > ```
  >
  > #### report

report button starts reporting issue and logger will print error to python console


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wsocket.gitbook.io/docs/guide/framework.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
