File: extension.go

package info (click to toggle)
golang-github-linuxdeepin-go-x11-client 0.6.3-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 1,656 kB
  • sloc: python: 944; sh: 38; makefile: 17
file content (148 lines) | stat: -rw-r--r-- 3,007 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package x

import (
	"sync"
)

type ReadErrorFunc func(*Reader) Error

type lazyReplyTag uint

const (
	lazyNone lazyReplyTag = iota
	lazyCookie
	lazyForced
)

type Extension struct {
	id               int
	name             string // extension-xname
	maxErrCode       uint8
	errCodeNameMap   map[uint8]string
	reqOpcodeNameMap map[uint]string
}

func (ext *Extension) Name() string {
	return ext.name
}

var nextExtId = 1

// only call it in init() func
func NewExtension(name string, maxErrCode uint8,
	errCodeNameMap map[uint8]string, reqOpcodeNameMap map[uint]string) *Extension {
	id := nextExtId
	nextExtId++
	return &Extension{
		id:               id,
		name:             name,
		maxErrCode:       maxErrCode,
		errCodeNameMap:   errCodeNameMap,
		reqOpcodeNameMap: reqOpcodeNameMap,
	}
}

type lazyReply struct {
	tag    lazyReplyTag
	reply  *QueryExtensionReply
	cookie QueryExtensionCookie
}

type extAndData struct {
	ext   *Extension
	reply *lazyReply
}

type ext struct {
	mu         sync.RWMutex
	extensions []extAndData
}

func (e *ext) grow(n int) {
	if n <= len(e.extensions) {
		return
	}

	logPrintf("ext grow %d -> %d\n", len(e.extensions), n)
	bigger := make([]extAndData, n)
	copy(bigger, e.extensions)
	e.extensions = bigger
}

func (e *ext) getById(id int) *extAndData {
	if id > len(e.extensions) {
		e.grow(id * 2)
	}
	return &e.extensions[id-1]
}

func (e *ext) getExtByMajorOpcode(majorOpcode uint8) *Extension {
	for _, extAndData := range e.extensions {
		ext := extAndData.ext
		lzr := extAndData.reply
		if ext != nil && lzr != nil && lzr.reply != nil {
			if majorOpcode == lzr.reply.MajorOpcode {
				return ext
			}
		}
	}
	return nil
}

func (e *ext) getExtErrName(errCode uint8) string {
	for _, extAndData := range e.extensions {
		ext := extAndData.ext
		lzr := extAndData.reply
		if ext != nil && lzr != nil && lzr.reply != nil {
			base := lzr.reply.FirstError
			max := lzr.reply.FirstError + ext.maxErrCode

			if base <= errCode && errCode <= max {
				return ext.errCodeNameMap[errCode-base]
			}
		}
	}
	return ""
}

func (e *ext) getLazyReply(conn *Conn, ext *Extension) (lzr *lazyReply) {
	extAndData := e.getById(ext.id)

	if extAndData.ext == nil {
		// init extAndData
		extAndData.ext = ext
		extAndData.reply = &lazyReply{tag: lazyNone}
	}
	lzr = extAndData.reply

	// lazyReply tag: lazyNone -> lazyCookie
	if lzr.tag == lazyNone {
		lzr.tag = lazyCookie
		lzr.cookie = QueryExtension(conn, ext.name)
	}
	return
}

func (e *ext) getExtData(c *Conn, ext *Extension) *QueryExtensionReply {
	lzr := e.getLazyReply(c, ext)

	// lazyReply tag: lazyCookie -> lazyForced
	if lzr.tag == lazyCookie {
		lzr.tag = lazyForced
		lzr.reply, _ = lzr.cookie.Reply(c)
	}
	return lzr.reply
}

func (c *Conn) GetExtensionData(ext *Extension) *QueryExtensionReply {
	c.ext.mu.Lock()
	data := c.ext.getExtData(c, ext)
	c.ext.mu.Unlock()
	return data
}

func (c *Conn) PrefetchExtensionData(ext *Extension) {
	c.ext.mu.Lock()
	c.ext.getLazyReply(c, ext)
	c.ext.mu.Unlock()
}