view redit-client-sm.el @ 69:34ac82ad8ca8

*** empty log message ***
author gongo
date Tue, 28 Oct 2008 19:39:19 +0900
parents bb40c73f7af3
children 858af2c8e77e
line wrap: on
line source

;; 	$Id$

;; defstruct
(require 'cl)

;;
;; REP Command
;;
;;  32 bits    32       32       32      32       32      textsiz
;; o-------o--------o--------o-------o--------o---------o-------...
;; +-------+--------+--------+-------+--------+---------+------+
;; | cmd   | session| editor | seqid | lineno | textsiz | text |
;; |       | id     | id     |       |        |         |      |
;; +-------+--------+--------+-------+--------+---------+------+
;; o-------header section (network order)---------------o-------...
;;
;; textsiz:
;;    This size is number of bytes for character string encoded with UTF8.
;;    
;; text:
;;    This size is variable length (textsiz).
;;

(defvar redit-client-process nil
  "Remote-edit client process.")

(defvar redit-client-buffer nil
  "Remote-edit client's buffer.")

(defvar redit-client-buffer-name nil
  "Remote-edit client's buffer-name.")

(defvar redit-client-buffer-number nil
  "Remote-edit client's buffer-number.")

;; editor local sequence number
(defvar redit-client-seqno 0
  "Remote-edit client's editor-id.")

(defvar redit-client-line-max-in-server nil
  "Value of point-max in server's buffer.")

(defvar redit-client-after-edited-line 1
  "Current cursor line of remote-edit client.")

(defvar redit-client-previous-line 1
  "Behind cursor line of remote-edit client.")

(defvar redit-max-string-length 1004
  "Read-Write max length of string.")

(defvar redit-process-filter-resume nil
  "String of the unprocessing in redit-client-process-filter")

;; REP が使用する文字コード
(defconst redit-string-coding 'utf-8
  "Default coding that REP use")

;; host
(defconst redit-process-hostname "localhost"
  "Default hostname that REP use")

;; port
(defconst redit-process-port 8766
  "Default port that REP use")

(defvar redit-client-before-begin-line nil
  "Begin edited line of redit-client-before-change-function")
(defvar redit-client-before-end-line nil
  "End edited line of redit-client-before-change-function")
(defvar redit-client-after-begin-line nil
  "Begin edited line of redit-client-after-change-function")
(defvar redit-client-after-end-line nil
  "End edited line of redit-client-after-change-function")


;; REP command header size (byte)
(defconst redit-command-header-size 24)

(defconst redit-command-offset-cmd   0)
(defconst redit-command-offset-sid   4)
(defconst redit-command-offset-eid   8)
(defconst redit-command-offset-seq  12)
(defconst redit-command-offset-lno  16)
(defconst redit-command-offset-siz  20)
(defconst redit-command-offset-txt  24)

;; Remote editor Command
(defconst repcmd-insert      6)
(defconst repcmd-insert-ack  7)
(defconst repcmd-delete      9)
(defconst repcmd-delete-ack 10)
(defconst repcmd-close      11)
(defconst repcmd-close2     12)
(defconst repcmd-nop        15)

;; Session Manager Command
(defconst smcmd-join        41)
(defconst smcmd-join-ack    42)
(defconst smcmd-put         45)
(defconst smcmd-put-ack     46)
(defconst smcmd-select      47)
(defconst smcmd-select-ack  48)
(defconst smcmd-select0     49)
(defconst smcmd-quit        53)
(defconst smcmd-quit-ack    54)
(defconst smcmd-quit2       67)
(defconst smcmd-quit2-ack   68)
(defconst smcmd-sync        82)
(defconst smcmd-sync-ack    83)

(defconst smeditor-sm    -1)
(defconst smeditor-merge -2)



(defconst redit-debug-flag t)
(defun redit-debug-message (string &rest args)
  (if (eq redit-debug-flag t)
      (message (apply 'format string args))))

;;;;;;;;;;;;;;;;;;
;; Queue struct ;;
;;;;;;;;;;;;;;;;;;
(defstruct Queue (front nil) (rear nil))

;; memo
;;  car: return first element of list
;;  cdr: return elements list since the second of list
;;  (ex.)
;;     (car '(rose violet daisy buttercup)) => rose
;;     (cdr '(rose violet daisy buttercup)) => (violet daisy buttercup)

;; enqueue item in queue
(defun enqueue (queue item)
  (let ((new-cell (list item)))
    (if (Queue-front queue)
  	;; update last cell
  	(setf (cdr (Queue-rear queue)) new-cell)
      ;; if queue is empty
      (setf (Queue-front queue) new-cell))
    (setf (Queue-rear queue) new-cell)))

;; dequeue
(defun dequeue (queue)
  (if (Queue-front queue)
      (prog1
  	  (pop (Queue-front queue))
  	(unless (Queue-front queue)
  	  ;; if queue is empty
  	  (setf (Queue-rear queue) nil)))))

(defun dequeue-all (queue)
  "clean queue"
  (while (Queue-front queue)
    (dequeue queue)))

(defun redit-get-command-from-queue (queue)
  (nth 0 (Queue-front queue)))
(defun redit-get-line-from-queue (queue)
  (nth 1 (Queue-front queue)))
(defun redit-get-uid-from-queue (queue)
  (nth 2 (Queue-front queue)))
(defun redit-get-text-from-queue (queue)
  (nth 3 (Queue-front queue)))

;;;;;;;;;;;;;;;;;;;;;;;;;
;; Session Info struct ;;
;;;;;;;;;;;;;;;;;;;;;;;;;

;; sid: Session ID
;; eid: Editor ID
;; prevline: この Session に対応するバッファで最後に編集された行
;; send_cmdlist: rep_command list from user to SessionManager
;; recv_cmdlist: rep_command list from SessionManager to user
(defstruct SessionInfo "a" (sid nil) (eid nil) (prevline 1)
  (send_cmdlist nil) (recv_cmdlist nil)
)

;; create and initialize
(defun redit-create-session-info (sid eid)
  (make-SessionInfo :sid sid
		    :eid eid
		    :send_cmdlist (make-Queue)
		    :recv_cmdlist (make-Queue)))

(defun redit-get-session-id-from-session-info (sinfo)
  (SessionInfo-sid sinfo))
(defun redit-get-editor-id-from-session-info (sinfo)
  (SessionInfo-eid sinfo))
(defun redit-get-sendqueue-from-session-info (sinfo)
  (SessionInfo-send_cmdlist sinfo))
(defun redit-get-recvqueue-from-session-info (sinfo)
  (SessionInfo-recv_cmdlist sinfo))

;; hash table of SessionInfo
(defun redit-sinfo-put-sid2buf (sid bufname)
  ""
  (setf (gethash sid htable-sid2bufname) bufname))
(defun redit-sinfo-get-sid2buf (sid)
  (gethash sid htable-sid2bufname))
(defun redit-sinfo-rm-sid2buf (sid)
  (remhash sid htable-sid2bufname))

(defun redit-sinfo-put-buf2sinfo (bufname sinfo)
  (setf (gethash bufname htable-bufname2sinfo) sinfo))
(defun redit-sinfo-get-buf2sinfo (bufname)
  (gethash bufname htable-bufname2sinfo))
(defun redit-sinfo-rm-buf2sinfo (bufname)
  (remhash bufname htable-bufname2sinfo))

;;;;;;;;;;;;;;;;;;;
;; pack / unpack ;;
;;;;;;;;;;;;;;;;;;;
(defun redit-pack-int-loop (num count)
  (if (> count 0)
      (concat
       (redit-pack-int-loop (/ num 256) (- count 1))
       (char-to-string (% num 256)))))

(defun redit-pack-int (num)
  (redit-pack-int-loop num 4))

(defun redit-pack (cmd sid eid seq lno siz)
  (concat
   (redit-pack-int cmd) (redit-pack-int sid) (redit-pack-int eid)
   (redit-pack-int seq) (redit-pack-int lno) (redit-pack-int siz)))

(defun redit-unpack-int-loop (pkt pos count)
  (if (> count 0)
      (+
       (* (string-to-char (substring pkt pos (1+ pos))) (expt 256 (1- count)))
       (redit-unpack-int-loop pkt (1+ pos) (1- count)))
    0
    ))

(defun redit-unpack-int (pkt pos)
  (redit-unpack-int-loop pkt pos 4))

(defun redit-make-packet (cmd sid eid seq lno siz text)
  (concat (redit-pack cmd sid eid seq lno siz) text))

(defun redit-get-command-from-pkt (pkt)
  (redit-unpack-int pkt redit-command-offset-cmd))
(defun redit-get-session-id-from-pkt (pkt)
  (redit-unpack-int pkt redit-command-offset-sid))
(defun redit-get-editor-id-from-pkt (pkt)
  (redit-unpack-int pkt redit-command-offset-eid))
(defun redit-get-sequence-id-from-pkt (pkt)
  (redit-unpack-int pkt redit-command-offset-seq))
(defun redit-get-line-number-from-pkt (pkt)
  (redit-unpack-int pkt redit-command-offset-lno))
(defun redit-get-text-size-from-pkt (pkt)
  (redit-unpack-int pkt redit-command-offset-siz))

;; text のサイズが指定されていればそれを使い、
;; そうでなければ、redit-get-text-size-from-pkt を実行する
(defun redit-get-text-from-pkt (pkt &optional _siz)
  (let ((size) (text) (offset redit-command-offset-txt))
    (setq size (if (null _siz) (redit-get-text-size-from-pkt pkt) _siz))
    (if (= size 0) ""
      (progn
	(setq text (substring pkt offset (+ offset size)))
	(decode-coding-string text redit-string-coding)))))



(defvar redit-client-send-command-queue (make-Queue))

(defvar htable-sid2bufname (make-hash-table))
(defvar htable-bufname2sinfo (make-hash-table))

;;;;;;;;;;;;;;;;;;
;; User Command ;;
;;;;;;;;;;;;;;;;;;

(defun redit-join ()
  "Allow this Emacs process to be a remote-edit session manager for client processes."
  (interactive)
  (let (bufname)
    (setq bufname (encode-coding-string
		   (buffer-name)
		   redit-string-coding))

    (if redit-client-process
	(progn
	  (set-process-sentinel redit-client-process nil)
	  (condition-case () ;;
	      (delete-process redit-client-process) (error nil))))
    
    (setq redit-client-process (open-network-stream
				"redit-client" nil redit-process-hostname
				redit-process-port))

    ;; called when the process changes state
    (set-process-sentinel redit-client-process 'redit-client-sentinel)
    
    ;; called when the process receive packet
    (set-process-filter redit-client-process 'redit-client-process-filter)
    
    ;; 送受信するデータはバイナリで受け取る。
    (set-process-coding-system redit-client-process 'binary 'binary)
    
    ;; プロセスが生きてるとき、 emacs を終了しようとすると
    ;; 「processがうんたらで、本当に切ってもいいの y/n」
    ;; って聞かれる。nil てやっておくと聞かれない。
    ;; quit を入れるんなら t にして有効にすべきなんだろうか。
    ;; 今は nil で
    (set-process-query-on-exit-flag redit-client-process nil)
    
    (if (string= "*scratch*" bufname) 
	(progn
	  ;; JOIN if buffer-name is "*scratch*"
	  (process-send-string redit-client-process
			       (redit-make-packet
				smcmd-join 0 0 0 0 0 ""))
	  (redit-debug-message "join-command: %d 0 0 0 0 0" smcmd-join)
	  )
      ;; PUT if buffer-name is not "*scratch*"
      (progn
	(process-send-string redit-client-process
			     (redit-make-packet
			      smcmd-put 0 0 0 0
			      (string-bytes bufname) bufname))
	(redit-debug-message "put-command: %d 0 0 0 0 %d %s"
			     smcmd-put (string-bytes bufname) (buffer-name))
	)
      )))

(defun redit-select()
  "Allow this Emacs process to be a remote-edit session manager for client processes."
  (interactive)
  (let (sid)
    (if (null redit-client-process)
	(progn
	  (setq redit-client-process (open-network-stream
				      "redit-client" nil redit-process-hostname
				      redit-process-port))

	  (set-process-sentinel redit-client-process 'redit-client-sentinel)
	  (set-process-filter redit-client-process 'redit-client-process-filter)
	  (set-process-coding-system redit-client-process 'binary 'binary)
	  (set-process-query-on-exit-flag redit-client-process nil)
	  ))

    (setq sid (read-minibuffer "Input session id: "))
    (process-send-string redit-client-process
			 (redit-make-packet
			  smcmd-select sid 0 0 0 0 ""))

    (redit-debug-message "select-command: %d %d 0 0 0 0 0" smcmd-select sid)
  ))

(defun redit-quit ()
  "quit"
  (interactive)
  ;; process kill とかしよう
  )

;; linenumで指定された行の編集をサーバへ送る
;; redit-client-process に insert コマンドと
;; バッファ(sid)番号、行番号、行の内容を送り、 Ack を受け取る
;; _text が指定されている場合、バッファのlinenumの文字列ではなく
;; _text で指定された文字列を送信する
(defun redit-client-insert (linenum &optional isnewline _text)
  "Send \"repcmd-insert\" to SessionManager.

If current buffer is not connected with SessionManager,
nothing is done (see `redit-client-exec-join', `redit-client-exec-put').

* REP command header

cmd : 6 (repcmd-insert).
sid : Session ID corresponding to current buffer.
eid : Editor ID corresponding to current buffer.
      (sid & eid are acquired from hash table `SessionInfo'.)
seq : Sequence Number. it can be acquired it from function `gen-seqno'.
lno : line number, LINENUM, that insert text.
siz : byte size of insert text.

* REP command text

String of the LINENUM line of current buffer. 
If the optional argument _TEXT is non-nil, text is _TEXT.
IF ISNEWLINE is t, line feed code is added behind text.
"
  (if redit-client-process
      (save-excursion
	(let (sinfo)
	  (setq sinfo (redit-sinfo-get-buf2sinfo (buffer-name)))
	  (if sinfo
	      (let ((sid (SessionInfo-sid sinfo))
		    (eid (SessionInfo-eid sinfo)) (packet) (text) (text-size))
		(setq text (if (null _text)
			       (encode-coding-string
				(get-string-from-buffer linenum)
				redit-string-coding)
			     (setq text _text)))
		(setq text-size (string-bytes text))

		(setq packet (redit-make-packet
			      repcmd-insert sid eid
			      (gen-seqno) linenum text-size text))
		
		;;(process-send-string redit-client-process packet)
		(enqueue redit-client-send-command-queue packet)
		
		(redit-debug-message
		 "[send] insert-command: %d %d %d %d %d %d %s"
		 repcmd-insert sid eid (gen-seqno)
		 linenum text-size text)
		)
	    )))
    (error "redit-client is not running.")))

;; linenum で指定した行の削除命令を redit-client-process に送信する
(defun redit-client-delete (linenum)
  "Send \"repcmd-delete\" to SessionManager.

If current buffer is not connected with SessionManager,
nothing is done (see `redit-client-exec-join', `redit-client-exec-put').

* REP command header

cmd : 9 (repcmd-delete).
sid : Session ID corresponding to current buffer.
eid : Editor ID corresponding to current buffer.
      (sid & eid are acquired from hash table `SessionInfo'.)
seq : Sequence Number. it can be acquired it from function `gen-seqno'.
lno : Delete line number, LINENUM.
siz : byte size of delete text

* REP command text

Deleted string of the LINENUM line of current buffer.
"
  (if redit-client-process
      (save-excursion
	(let (sinfo)
	  (setq sinfo (redit-sinfo-get-buf2sinfo (buffer-name)))
	  (if sinfo
	      (let ((sid (SessionInfo-sid sinfo))
		    (eid (SessionInfo-eid sinfo)) (packet) (text) (text-size))
		(setq text (get-string-from-buffer linenum))
		(setq text-size (string-bytes text))

		(setq packet (redit-make-packet
			      repcmd-delete sid eid
			      (gen-seqno) linenum text-size text))
	    
		;;(process-send-string redit-client-process packet)
		(enqueue redit-client-send-command-queue packet)

		(redit-debug-message
		 "[send] delete-command: %d %d %d %d %d %d %s"
		 repcmd-delete sid eid (gen-seqno)
		 linenum text-size text)
		)
	    )))
    (error "redit-client is not running.")))

(defun redit-client-replace (linenum &optional text)
  "Send \"repcmd-delete\" and \"redit-insert-line-command
to SessionManager.

`redit-replace-command' is obsolete command.
Now, replace command is done by using `redit-client-delete' and
`redit-client-insert'.

For example, now buffer

1: hoge
2: void
3: elisp

argument LINENUM = 2, TEXT = \"redit-client\"

result

1: hoge
2: redit-client
3: elisp
"
  (redit-client-delete linenum)
  (redit-client-insert linenum text))

(defun redit-client-send-rep-command ()
  (let (command)
    (setq command (dequeue redit-client-send-command-queue))
    (while command
      (process-send-string redit-client-process command)
      (setq command (dequeue redit-client-send-command-queue))
  ))
)

;; proc == redit-client-process
;; string == redit-client-process からの output
(defun redit-client-process-filter (proc string)
  ""
  (remove-hook 'before-change-functions
	       'redit-client-before-change-function)
  (remove-hook 'after-change-functions
	       'redit-client-after-change-function)
    
  (let (cmd sid eid seq lno siz txt allsize cursize)
    ;; 前回に余った奴があれば、それを前方追加する
    (setq string (concat redit-process-filter-resume string))
    (setq allsize (length string))
    
    (block loop
      ;; process-filter が受け取れるのは1024byteまで。
      ;; なので、string に入っているパケットが途中で切れてる可能性がある
      (while (> allsize redit-command-header-size)
	(setq siz (redit-get-text-size-from-pkt string))
	
	;; ヘッダ (redit-command-header-size) + テキストサイズ
	(setq cursize (+ redit-command-header-size siz))

	;; パケットが 1024 byte の壁で途切れてる場合、
	;; テキストが読めないので、ループを抜ける
	(if (> cursize allsize) (return-from loop))

	(setq cmd (redit-get-command-from-pkt string))
	(setq sid (redit-get-session-id-from-pkt string))
	(setq eid (redit-get-editor-id-from-pkt string))
	(setq seq (redit-get-sequence-id-from-pkt string))
	(setq lno (redit-get-line-number-from-pkt string))
	(setq txt (redit-get-text-from-pkt string))
	
	;; command がどの命令かを判断し、対応した処理をする。case みたい
	(cond
	 ((if (= cmd repcmd-insert)
	      (redit-client-exec-insert sid lno txt)
	    ))
	 ((if (= cmd repcmd-delete)
	      (redit-client-exec-delete sid lno)
	    ))
	 ((if (= cmd smcmd-join-ack)
	      (redit-client-exec-join txt sid eid)))
	   
	 ((if (= cmd smcmd-put-ack)
	      (redit-client-exec-put sid eid)))
	 )

	(setq allsize (- allsize cursize))
	;; string の分割
	(setq string (substring string cursize))
	)
      )
    )
      
  ;; 途切れたやつは次の process-filter の string に入っているので
  ;; この時点で余った奴を保存し、
  ;; 次の process-filter の string の前に連結する
  (setq redit-process-filter-resume string)
  
  (add-hook 'before-change-functions
	    'redit-client-before-change-function t)
  (add-hook 'after-change-functions
	    'redit-client-after-change-function t)
  )

(defun real-count-lines (currentp)
  (+ (count-lines (point-min) currentp)
     (if (= (save-excursion (goto-char currentp) (current-column))
	    0)
	 1  0)))

(defun redit-client-before-change-function (begin end)
  "This function was added at the hook `before-change-functions' list.
It call before each text change of all buffer.
Two arguments are passed to each function: the positions of
the beginning BEGIN and end END of the range of old text to be changed.

In this function, the line of beginning, end and max line
of old buffer are only secured.
"
  (let (sinfo)
    (setq redit-client-before-begin-line (real-count-lines begin))
    (setq redit-client-before-end-line (real-count-lines end))

    (setq sinfo (redit-sinfo-get-buf2sinfo (buffer-name)))
    (if sinfo
	(progn
	  ;; previous edit line
	  (let (prev-edit-line)
	    (setq prev-edit-line (SessionInfo-prevline sinfo))
	    (if (/= prev-edit-line redit-client-before-begin-line)
		(progn
		  (redit-client-replace prev-edit-line))))

	  ;; delete-line
	  (let (editl)
	    (setq editl redit-client-before-end-line)
	    (if (> editl redit-client-before-begin-line)
		(while (>= editl redit-client-before-begin-line)
		  (redit-client-delete editl)
		  (setq editl (1- editl)))))
	  )
      )
    )  
  )

(defun redit-client-after-change-function (begin end length)
  "This function was added at the hook `after-change-functions' list.
It call after each text change of all buffer.
Three arguments are passed to each function: the positions of
the beginning BEGIN and end  END of the range of changed text,
and the length LENGTH in bytes of the pre-change text replaced by that range.

If current buffer (edited buffer) is not connected with SessionManager,
nothing is done (see `redit-client-exec-join', `redit-client-exec-put').

The edited lines is checked, and insert/delete commands are issued.
The change by the same line is disregarded.
"
  (let (sinfo)
    (setq sinfo (redit-sinfo-get-buf2sinfo (buffer-name)))
    (if sinfo
	(let ((editl) (cur-max-line) (max-line-diff)
	      (prev-edit-line) (lf-flg nil))

	  (setq redit-client-after-begin-line (real-count-lines begin))
	  (setq redit-client-after-end-line (real-count-lines end))

	  ;; 詳しくは ChangeLog [2008-08-28] を見て
	  (if (= redit-client-before-begin-line redit-client-after-end-line)
	      ;; case delete
	      (if (/= redit-client-before-begin-line
		      redit-client-before-end-line)
		  (redit-client-insert redit-client-before-begin-line))

	    (progn
	      ;; case insert or replace
	      (setq editl redit-client-before-begin-line)
	      (while (< editl redit-client-after-end-line)
		(redit-client-insert editl)
		(setq editl (1+ editl)))

	      ;; case insert
	      (if (= redit-client-before-begin-line
		     redit-client-before-end-line)
		  (redit-client-delete redit-client-after-end-line))

	      (redit-client-insert redit-client-after-end-line)
	      )
	    )

	  (redit-client-send-rep-command)
	  (setf (SessionInfo-prevline sinfo) redit-client-after-end-line)
))))

(defun redit-client-exec-insert (sid linenum text)
  "Call when received \"repcmd-insert\" from SessionManager.
see. `redit-client-process-filter'.

TEXT is inserted in line LINENUM of buffer corresponding to SID.

For example, now buffer

1: hoge
2: void
3: elisp

argument LINENUM = 2, TEXT = \"redit-client\"

result

1: hoge
2: redit-client
3: void
4: elisp"

  (redit-debug-message "[recv] insert-line: Session[%d] linenum = %d text = %s"
		       sid linenum text)

  (let (curlineno maxlineno bufname sinfo)
    (setq bufname (redit-sinfo-get-sid2buf sid))

    (save-excursion
      (set-buffer bufname)
      (goto-line linenum)
      (setq curlineno (real-count-lines (point)))
      (setq maxlineno (real-count-lines (point-max)))

      (if (> linenum curlineno)
	  ;; buffer の 最後の行番号が、linenum に足りない場合、
	  ;; その行数だけ改行し、その行へ移動する。
	  (progn (end-of-line)
		 (newline (- linenum curlineno))
		 (goto-line linenum)))

      (if (= curlineno 1)
	  (progn
	    (beginning-of-line)
	    (insert (concat text (if (/= maxlineno 1) "\n" ""))))
	(progn
	  (goto-line (1- curlineno))
	  (end-of-line)
	  (insert (concat "\n" text))))
      )))

(defun redit-client-exec-delete (sid linenum)
  "Call when received \"repcmd-delete\" from SessionManager.
see. `redit-client-process-filter'.

Line LINENUM of buffer corresponding to SID is deleted.

For example, now buffer

1: hoge
2: void
3: elisp

argument LINENUM = 2

result

1: hoge
2: elisp
"
  (redit-debug-message "[recv] delete-line: Session[%d] linenum = %d"
		       sid linenum)

  (let ((bufname (redit-sinfo-get-sid2buf sid))
	(maxlineno (real-count-lines (point-max)))
	diff)
    (save-excursion
      (set-buffer bufname)
      (setq diff (goto-line linenum))
      ;;(if (= diff 0)
      (if (is-value-in-range 1 linenum maxlineno)
	  (progn
	    (delete-region (progn (beginning-of-line) (point))
			   (progn (end-of-line) (point)))
	    ;; 指定された行自体を削除
	    (if (= (point) (point-max))
		(delete-backward-char 1)
	      (delete-char 1)))
	)
      )))

(defun redit-client-exec-join (filename sid eid)
  "Call when received \"smcmd-join-ack-command\" from SessionManager.
see. `redit-client-process-filter'.

SID is id of session which client participation.
EID is id of client in session.
FILENAME file name used by session.

Buffer that name is the same FILENAME is generated, and move to it.
`SessionInfo' is created by using SID and EID. 
"
  (let (bufname sinfo)
    (setq sinfo (redit-create-session-info sid eid))

    ;; SessionManager から受け取った、このセッションのファイル名を
    ;; バッファ名とし、そのバッファを生成する。
    (setq bufname (buffer-name (generate-new-buffer filename)))

    ;; SessionID => BufferName => SessionInfo のテーブル生成
    (redit-sinfo-put-sid2buf sid bufname)
    (redit-sinfo-put-buf2sinfo bufname sinfo)

    (switch-to-buffer bufname)

    (redit-debug-message "join-ack: Session [%d] %s" sid bufname)
    (redit-debug-message "Your editor id = %d" eid)

))

;; //引き数で与えられた string から Session IDを取得する
;; 新仕様で、(put = ファイル有りjoin) ってことになって
;; editor id を返すことになったので、sid と共に eid もセーブする
(defun redit-client-exec-put (sid eid)
  (let (sinfo bufname)
    ;; create SessionInfo
    (setq sinfo (redit-create-session-info sid eid))

    ;; put (ファイル名付きjoin) を行ったバッファで
    ;; すでにファイルが開かれている(はずな)ので、それをバッファ名とする
    (setq bufname (buffer-name))

    ;; SessionID => BufferName => SessionInfo のテーブル生成
    (redit-sinfo-put-sid2buf sid bufname)
    (redit-sinfo-put-buf2sinfo bufname sinfo)

    (switch-to-buffer bufname)
    
    (redit-debug-message "put-ack Session [%d] %s" sid bufname)
    (redit-debug-message "Your editor id = %d" eid)
))

(defun redit-client-exec-sync (sid)
  (let ((max-line (real-count-lines (point-max)))
	(curline 1))
    (while (<= curline max-line)
      (redit-client-delete curline)
      (redit-client-insert curline)

      (accept-process-output redit-client-process)

      (setq curline (1+ curline))
      )
    )
  )


;; プロセスの状態を見て、対応したメッセージを表示
(defun redit-client-sentinel (proc msg)
  (cond ((eq (process-status proc) 'exit)
	 (redit-debug-message "Client subprocess exited"))
	((eq (process-status proc) 'signal)
	 (redit-debug-message "Client subprocess killed"))))

(defun gen-seqno ()
  "generate editor local sequence number."
  (setq redit-client-seqno (+ redit-client-seqno 1)))

(defun get-string-from-buffer (linenum &optional _bufname)
  (let (bufname)
    (if (null _bufname)
	(setq bufname (buffer-name))
      (setq bufname _bufname))

    (save-excursion
      (set-buffer bufname)
      (goto-line linenum)
      (buffer-substring (progn (beginning-of-line) (point))
			(progn (end-of-line) (point)))
      )
    )
  )

(defun is-value-in-range (min value max)
  (if (and (<= min value) (<= value max))
      t nil))