Fuzion Logo
fuzion-lang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

net/channel.fz


# This file is part of the Fuzion language implementation.
#
# The Fuzion language implementation is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3 of the License.
#
# The Fuzion language implementation is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License along with The
# Fuzion language implementation.  If not, see <https://www.gnu.org/licenses/>.


# -----------------------------------------------------------------------
#
#  Tokiwa Software GmbH, Germany
#
#  Source code of Fuzion standard library feature net.channel
#
# -----------------------------------------------------------------------


# a channel encapsulates an open network resource
# that can be read from and written to.
# channels are usually installed by a successfully connected client
# or a by a newly accepted server connection.
#
# Note that even though UDP is a connection-less protocol its
# usage in fuzion does not differ from TCP except for the following
# caveats.
# 1) Reading a Datagram with a buffer not large enough to hold
# all data will lead to the rest of the datagram being dropped.
# 2) writing to a channel installed by `server.accept` will result in an error.
# 3) reading from a channel installed by `client ...` will block indefinitely.
#
module:public channel(T type, desc outcome i64, auto_close bool, m effect_mode.val) : effect m
is

  # get the last error that occurred
  last_error => desc.bind unit (_ -> unit)


  # is this channel still active?
  is_active => desc.ok


  # shorthand to replace the effect installed in env
  # and return a
  replace(X type, a X) X =>
    replace
    a


  # read bytes from channel
  public read(max_bytes i32) outcome (array u8) =>
    # close channel on certain read errors?
    replace (match desc
      d i64 => fuzion.sys.net.read d max_bytes
      e error => e)


  # NYI when to stop reading?
  public read outcome String =>
    # read buffer in bytes
    buffer_size i32 := 10

    match desc
      d i64 =>
        l := (1..)
          .reduce((list u8), (list u8).empty, ((r,_) ->
            match read buffer_size
              e error => abort r
              a array u8 => r ++ a))
        String.from_bytes l
      e error =>
        e


  # write data to channel
  public write(data Sequence u8) outcome unit =>
    # close channel on certain write errors?
    match desc
      d i64 => replace (fuzion.sys.net.write d data.as_array)
      e error => e


  # close the channel
  public close is
    if auto_close
      match desc
        d i64 =>
          match fuzion.sys.net.close d
            unit =>
              channel T (error "not initialized") false effect_mode.repl
            e error =>
              channel T e false effect_mode.repl
        e error =>
          channel T (error "not initialized") false effect_mode.repl
    unit


  # get the peer's ip address (tcp)
  public get_peer_address outcome (list u8) =>
    match desc
      sockfd i64 => fuzion.sys.net.get_peer_address sockfd
      e error => e


  # get the peer's port (tcp)
  public get_peer_port outcome u16 =>
    match desc
      sockfd i64 => fuzion.sys.net.get_peer_port sockfd
      e error => e



# short hand to install a new channel of type T
module channel(T type, desc outcome i64, auto_close bool) =>
  (channel T).close
  channel T desc auto_close effect_mode.repl



# short hand to get the currently installed channel of type T
public channel(T type) =>
  if !effect.is_installed (channel T)
    channel T (error "not initialized") false effect_mode.default
  (channel T).env