iiegor / xat-server

A Node.js private server of xat.com
8 stars 2 forks source link

Power handling behavior #18

Closed iiegor closed 8 years ago

iiegor commented 8 years ago

Hello, in this issue we are going to discuss what would be the best way to load/handle the user powers when the user is logging in.

Actually, we are sending those d4, d5, d6, d9 which are hardcoded (see user.coffee#L22). Instead I thought on something like this:

getPowers = (id) =>  new Promise (resolve, reject) =>
  database.exec('SELECT * FROM userpowers WHERE userid = ?', [id]).then (upowers) =>
    database.exec('SELECT * FROM powers', []).then (spowers) =>
      vals = new Array()
      p = new Array()
      dO = ''
      powerO = ''

      for u in spowers
        vals[u["id"]] = new Array(u["section"], u["subid"])

        p[u["section"]] = 0 if !p[u["section"]]

      for u in upowers
        if parseInt(u["count"]) >= 1 and vals[u["powerid"]] and p[vals[u["powerid"]][0]]
          val = if parseInt(u['count']) > 1 then parseInt(u['count']) - 1 else 1
          str = "#{u['powerid']}=#{val}|"
          dO += str

          powerO += str if parseInt(u['count']) > 1

          p[vals[u["powerid"]][0]] += vals[u["powerid"]][1]

      vars = ''
      for value, index in p
        vars += 'd' + (index.substr(1) + 4) + '="' + value + '" ' 

      resolve(vars)

then the value of the resolved promise will be appended to the login packet as a raw packet.

Obviously this code is an early prototype (doesn't work) and was extracted from an old php server, maybe we can do something better :)

Hotallday commented 8 years ago
public function getPowers($pV = array())
    {
        $this->pendingLogin = false;
        if($this->days < 1)
        {
            for($i = 0; $i <= $this->parent->config->pcount; $this->{'p' . $i++} = 0);
            return true;
        }

        $powers = $this->parent->mysql->fetch_array('select * from `userpowers` where `userid`=' . $this->id . ';');
        $powerv = $this->parent->mysql->fetch_array('select `id`, `section`, `subid`, `limited`, `p` from `powers` where `name` not like \'%(Undefined)%\';');
        $pv = $test = $final = array();
        foreach($powerv as $power)
        {
            $pv[$power['id']] = array('sect' => $power['section'], 'sub' => (int) $power['subid']);
            $test[$power['section']] = 0;
            $last[$power['section']] = 0;
            $last2[$power['section']] = 0;
        }

        foreach($powers as $power)
        {
            $test[$pv[$power['powerid']]['sect']] += $pv[$power['powerid']]['sub'];
        }

        foreach($test as $sect => $val)
        {
            if((int) $val != (int) $this->{$sect . 'v'})
            {
                $this->pendingLogin = true;
                return false;
            }
        }

        foreach($powers as $power)
        {
            if(isset($pv[$power['powerid']]))
            {
                $power = $pv[$power['powerid']];
                if((int) $this->{$power['sect'] . 'v'} & $test[$power['sect']])
                {
                    if(!((int) $power['sub'] & $test[$power['sect']]))
                    {
                        $this->pendingLogin = true;
                        return false;
                    }

                    if(!($this->{'m' . substr($power['sect'], 1)} & (int) $power['sub']))
                    {
                        $last[$power['sect']] += (int) $power['sub'];
                    }

                    if(($this->{'m' . substr($power['sect'], 1)} & (int) $power['sub']) || !($this->{'m' . substr($power['sect'], 1)} & (int) $power['sub']))
                    {
                        $last2[$power['sect']] += (int) $power['sub'];
                    }

                }
            }
        }

        $this->pStr = '';
        foreach($test as $sect => $u)
        {
            $this->{$sect} = $last[$sect];
            $this->pStr .= $sect . '="' . $this->{$sect} . '" ';
        }

        $this->pStr2 = '';
        foreach($test as $sect => $u)
        {
            $this->{'m'.$sect} = $last2[$sect];
            $this->pStr2 .= $sect . '="' . $this->{'m'.$sect} . '" ';
        }

        //$powerv = $this->parent->mysql->fetch_array('select `id`, `section`, `subid`, `limited`, `p` from `powers` where `name` not like \'%(Undefined)%\';');

        foreach($powerv as $i => $power) {
            if($this->hasPower($power['id'])) {
                if(!$this->hasDBPower($power['id'], $powers)) {
                    $this->pendingLogin = true;
                    return false;
                }
            }
            if($power['p']) {
                if($this->hasPower(213)) {
                    if(!$this->hasDBPower($power['id'], $powers)) {
                        $this->pendingLogin = true;
                        return false;
                    }
                }
                if($this->hasPower(0) && !$power['limited']) {
                    if(!$this->hasDBPower($power['id'], $powers)) {
                        $this->pendingLogin = true;
                        return false;
                    }
                }
            }
        }

        //$powers2 = $this->parent->mysql->fetch_array('select `id`, `section`, `subid`, `limited`, `p` from `powers` where `name` not like \'%(Undefined)%\';');

        return true;
    }

This is using a new php source. Just in case you wanted to see how they do it.

huumanoid commented 8 years ago

dO and PowerO are the same things, aren't they?

I like your code, i think we don't have to invent something conceptually different. There is nothing to invent.

If we don't worry about xat compatibility, we may send only counts of all powers splitted by '|'. It seems easy to implement but may cause significant increase in traffic.

Also we may use this sql query

SELECT [powers.powerid,] ifnull(count, 0) AS count FROM powers LEFT JOIN userpowers ON (powers.powerid = userpowers.powerid) WHERE userpowers.userid = ? or userpowers.userid IS NULL

to extract an array of powers count. It's easy to construct d[i] and dO using this array, but i don't know what's with performance.

Any thoughts?

iiegor commented 8 years ago

@Hotallday Thanks, this will be useful :) @HuuMaNoID The main feature of this project is to imitate as completely as possible the original xat server behavior so doing what you said is not an option unfortunately. Maybe we can find another way?

I'm not aware of the performance of doing the count in the server or in the query so maybe a simple benchmark can resolve our doubts.

iiegor commented 8 years ago

A very experimental version of this was landed in https://github.com/iiegor/xat-server/commit/16b020827816eb03046e1ec5c9cccca4bcbf8447, there are a lots of thing to fix regarding this and we still need to send the duplicated powers count.