tinode发送文件

附件

  1. 会在数据库的fileuploads表里有记录

    	{ 
    	    "_id" : "-W1iX9nmOTM", 
    	    ...
    	    "location" : "uploads\\7fwwex6z4y4tg",
    	}
    
  2. mesages表里的记录有fileuploads对应的_id字段

    • /v0/file/s/-W1iX9nmOTM.jpg
    • 上面的链接也是前端发送给后端的,后端根据-W1iX9nmOTM.jpg找到fileuploads._id的记录然后根据location字段提供下载
  3. server/store/store.go里的Save里处理,记录到fileuploads表里也在这里处理的

    	func (MessagesObjMapper) Save(msg *types.Message, readBySender bool) error {
    		if header, ok := msg.Head["attachments"]; ok {
    			...
    		}
    		
    	}
    
  4. 太大的文件不能发送

  5. 如果token的时效设的太短,那么会导致失败,因为要提供token

直接发送图片

和客户端的交互记录

2020/03/30 17:03:47 in: {"pub":{"id":"98368","topic":"usry8McI40hGwk","noecho":true,"head":{"mime":"text/x-drafty"},"content":{"txt":" ","ent":[{"tp":"IM","data":{"mime":"image/png","val":"iVBORw0KGgoAAAANSUhEUgAAAs8AAAGlCAYAAAAF9RsWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAK0mSURBVHhe7Z0vsB1luq+vG8c4XDAQQxyYSwwUglzMYGYuhsIwmGTEqWAYDFRMYoaMuCnESRQxSWESBSNOKiZgDoo5BsYMDnePu2rf/SzWL/Pud3//utdae+3e+T1VXcleq/v7391Pv+vr7v9xyIEXL168ePHixYsXL16Glv9xYJaD+8sYY4wxZj9YnheI+8sYY4wxZj9YnheI+8sYY4wxZj9YnheI+8sYY4wxZj9<...>"}}]}}}'

2020/03/30 17:03:47 out: mt = `1`, `{"ctrl":{"id":"98368","topic":"usry8McI40hGwk","params":{"seq":32},"code":202,"text":"accepted","ts":"2020-03-30T09:03:47.813Z"}}`

2020/03/30 17:03:47 out: mt = `1`, `{"data":{"topic":"usrJnmU7EGAAX4","from":"usrJnmU7EGAAX4","ts":"2020-03-30T09:03:47.813Z","seq":32,"head":{"mime":"text/x-drafty"},"content":{"ent":[{"data":{"height":421,"mime":"image/png","name":"微信图片_20200104162412.png","val":"","width":719},"tp":"IM"}],"fmt":[{"len":1}],"txt":" "}}}`

2020/03/30 17:03:48 in: '{"note":{"topic":"usrJnmU7EGAAX4","what":"recv","seq":32}}' ip='127.0.0.1:57030' 

2020/03/30 17:03:48 out: mt = `1`, `{"info":{"topic":"usry8McI40hGwk","from":"usry8McI40hGwk","what":"recv","seq":32}}`

2020/03/30 17:03:49 in: '{"note":{"topic":"usry8McI40hGwk","what":"read","seq":32}}' ip='127.0.0.1:56702' 

2020/03/30 17:03:49 in: '{"note":{"topic":"usrJnmU7EGAAX4","what":"read","seq":32}}' ip='127.0.0.1:57030' 

2020/03/30 17:03:49 out: mt = `1`, `{"info":{"topic":"usry8McI40hGwk","from":"usry8McI40hGwk","what":"read","seq":32}}`

图片链接

  1. 发送方的地址: blob:http://127.0.0.1:6060/5740db06-cb63-4bfd-95eb-cc4e4992eb77
  2. 接受方的地址: blob:http://127.0.0.1:6060/f0cff750-171c-4d46-9c4e-30767d3a50ec
  3. 这2个地址只能在各自的浏览器里展现,在其他地方都是无法打开,原因见下面的blob
    • chrome提示
      	找不到您的文件该文件可能已被移至别处或遭到删除。
      	ERR_FILE_NOT_FOUND
      
    • firfox提示
      	呃…这个网址好像有错。
      
      	请检查网址是否正确,然后重试。
      
  4. 如果在能打开的地方,地址前缀不使用blob:http://,只使用http://会提示
    	{
    		ctrl: {
    			code: 404,
    			text: "Not Found",
    			ts: "2020-03-31T07:30:10.44Z"
    		}
    	}
    
blob协议
  1. 一般的用法是用来预览图片: blob例子
    • 做到和tinode一样在同一个浏览器新的标签页也可以访问图片,把这个url放到全局对象上:
      	let u = window.URL.createObjectURL(e.target.files[0])
      	console.log("可以全局访问的对象",u);
      
  2. Blob 对象表示一个不可变、原始数据的类文件对象。Blob 表示的不一定是JavaScript原生格式的数据: MDN-blob
  3. 应该只是在前端,其实不涉及后端

疑问

  1. 这个图片放在哪儿了?
    • 是直接发送的二进制数据,这些数据作为聊天内容的一部分是放在数据库的
  2. 图片链接是怎么生成的?
    • 见上面的blob
  3. pub后是怎么处理这个消息的,看到是直接塞到sub的一个channel了
    • 在有sub的情况下的处理代码

      	if sub := s.getSub(expanded); sub != nil {
      		// This is a post to a subscribed topic. The message is sent to the topic only
      		log.Printf("sub != nil, sub = %+v", sub)
      		sub.broadcast <- data
      	}
      
    • sub对应的数据结构

      	// Subscription is a mapper of sessions to topics.
      	type Subscription struct {
      		// Channel to communicate with the topic, copy of Topic.broadcast
      		broadcast chan<- *ServerComMessage  // 这个channel只能塞,没法取啊,怎么跟topic关联上的?
      	
      		// Session sends a signal to Topic when this session is unsubscribed
      		// This is a copy of Topic.unreg
      		done chan<- *sessionLeave
      	
      		// Channel to send {meta} requests, copy of Topic.meta
      		meta chan<- *metaReq
      	
      		// Channel to ping topic with session's user agent
      		uaChange chan<- string
      	}
      
    • channel是引用类型,在server/topic.go里,作了引用类型的值传递,第一步塞入到Subscription的

      	sess.addSub(t.name, &Subscription{
      		broadcast: t.broadcast,    // 这里作了2个channel类型的赋值,就是引用类型的值传递,
      		done:      t.unreg,
      		meta:      t.meta,
      		uaChange:  t.uaChange})
      	t.addSession(sess, asUid)
      
    • server/topic.go里的run函数处理了

      	func (t *Topic) run(hub *Hub) {
      		case msg := <-t.broadcast:
      			...
      	}
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是对vx6中mkfs.c代码的注释: ``` /* * mkfs.c - file system initialization program */ #include "param.h" #include "buf.h" #include "inode.h" #include "filsys.h" #define NINOBLK (BSIZE/sizeof(struct dinode)) #define NDIRECT (BSIZE/sizeof(struct direct)) struct filsys sblock; /* the file system super block */ int fmod = 0; /* is the file system already modified? */ int fso, fsi; /* file system device file descriptors */ unsigned int fmax; /* number of blocks in file system */ unsigned char *fbuf; /* buffer for file system super block */ /* * main - file system initialization program */ main(argc, argv) int argc; char *argv[]; { register struct dinode *ip; struct direct dp; int n, i, j; daddr_t bn; char filename[50]; /* Open file system device file */ if(argc < 2) { printf("Usage: mkfs filsys\n"); exit(1); } fso = open(argv[1], 1); if(fso < 0) { printf("Can't open %s\n", argv[1]); exit(1); } /* Compute the number of blocks in the file system */ fsi = open(argv[1], 0); fmax = 0; while(read(fsi, fbuf, BSIZE) == BSIZE) fmax++; close(fsi); /* Compute the number of inodes in the file system */ sblock.s_isize = roundup(fmax/16, BSIZE) + 2; sblock.s_fsize = fmax; /* Initialize the super block */ sblock.s_flock = 0; sblock.s_ilock = 0; sblock.s_fmod = 0; sblock.s_ronly = 0; sblock.s_time = 0; sblock.s_tfree = fmax; sblock.s_tinode = sblock.s_isize * NINOBLK; sblock.s_dinfo[0] = 0; sblock.s_dinfo[1] = 0; sblock.s_dinfo[2] = 0; sblock.s_dinfo[3] = 0; sblock.s_dinfo[4] = 0; sblock.s_dinfo[5] = 0; sblock.s_dinfo[6] = 0; sblock.s_dinfo[7] = 0; /* Write the super block to disk */ lseek(fso, SUPERBOFF, 0); write(fso, &sblock, sizeof(sblock)); /* Initialize the inode blocks */ n = sblock.s_isize; ip = (struct dinode *) fbuf; for(i = 2; i < n; i++) { bzero(fbuf, BSIZE); for(j = 0; j < NINOBLK; j++, ip++) { ip->di_mode = 0; ip->di_nlink = 0; ip->di_uid = 0; ip->di_gid = 0; ip->di_size = 0; bn = itod(i) * BSIZE + j * sizeof(struct dinode); lseek(fso, bn, 0); write(fso, ip, sizeof(struct dinode)); } } /* Initialize the root directory */ bzero(fbuf, BSIZE); ip = (struct dinode *) fbuf; ip->di_mode = IFDIR | 0777; ip->di_nlink = 2; ip->di_uid = 0; ip->di_gid = 0; ip->di_size = sizeof(struct direct); ip->di_addr[0] = itod(2); lseek(fso, itod(2) * BSIZE, 0); write(fso, fbuf, BSIZE); /* Add "." and ".." entries to the root directory */ dp.d_ino = 1; strncpy(dp.d_name, ".", DIRSIZ); lseek(fso, itod(2) * BSIZE, 0); write(fso, &dp, sizeof(dp)); dp.d_ino = 1; strncpy(dp.d_name, "..", DIRSIZ); write(fso, &dp, sizeof(dp)); /* Initialize the free block list */ bzero(fbuf, BSIZE); fbuf[0] |= BUSY; for(i = 2; i < fmax; i++) write(fso, fbuf, BSIZE); /* All done */ close(fso); exit(0); } ``` 上面代码的主要作用是: 1. 定义了文件系统超级块结构体 `struct filsys` 和磁盘上的 `inode` 结构体 `struct dinode`。 2. 定义了文件系统初始化工具 `mkfs` 的全局变量,包括文件系统设备文件描述符、文件系统设备文件的块数量、文件系统超级块等。 3. 通过读取命令行参数,打开文件系统设备文件。 4. 计算文件系统中的块数量和inode数量,并初始化文件系统的超级块结构体。 5. 将文件系统的超级块写入磁盘,并初始化inode块和根目录。 6. 最后,初始化空闲块链表,写入磁盘,完成文件系统的初始化工作。 总体而言,mkfs.c的作用是初始化vx6文件系统,并在磁盘上创建一个文件系统,以便操作系统可以使用这个文件系统来存储和管理文件和目录等数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值